XenevaOS
Loading...
Searching...
No Matches
sched.h
Go to the documentation of this file.
1#ifndef __LINUX_SCHED_H__
2#define __LINUX_SCHED_H__
3
4/*
5 * DCL <linux/sched.h> -- task state, `current`, and schedule().
6 *
7 * Xeneva has no sleeping scheduler for kernel context: there is nothing to
8 * switch away to, so `schedule()` cannot do what mainline's does. Pretending
9 * otherwise would be the worst kind of wrongness here -- a driver that
10 * believes it slept would loop forever on a condition that never arrives.
11 * Instead the honest shape is kept and the sleeps are made *short and
12 * bounded*, which is what the tty code actually needs from them:
13 *
14 * schedule()
15 * Sleeps a millisecond. tty_open() retries on -EAGAIN with
16 * `schedule(); goto retry_open;` (tty_io.c:2127 and :2153) -- with a
17 * no-op that becomes a hard spin against a condition only an
18 * interrupt can change, so a millisecond of yield is the difference
19 * between a retry loop and a locked-up console.
20 *
21 * signal_pending() / fatal_signal_pending()
22 * Always 0. Xeneva has no signals to deliver, so no wait can be broken
23 * out of this way. That is recorded rather than papered over, because
24 * it has one real consequence: uart_wait_modem_status() (serial_core.c:
25 * 1200) loops until a modem-status interrupt or a signal, so TIOCMWAIT
26 * on a port that never raises one never returns. Closing that needs a
27 * bounded wait at the serial_core call site -- stage 4's list, not a
28 * lie in this header.
29 *
30 * current
31 * One task_struct per kernel context, with `comm` filled from the
32 * running thread. `current` is an object-like macro, exactly as on
33 * mainline, which means a struct member literally named `current`
34 * would not compile against this header. Nothing in the tty/serial
35 * set has one (the only `file->current` in the tree is Xeneva's own
36 * loader and FAT code, which do not include DCL headers).
37 *
38 * `signal->tty` is NULL: it is read by tty_io.c:2280 in tiocsti(), the
39 * TIOCSTI gate, and only there. NULL makes TIOCSTI answer -EPERM for a
40 * non-admin, which is the safe direction -- TIOCSTI injects keystrokes
41 * into another terminal and is disabled by default upstream for
42 * exactly that reason.
43 *
44 * task_lock()/task_unlock() are the one guard tty_io.c takes directly
45 * (guard(task_lock)(p) at :3046), so the class lives here with the primitive.
46 */
47
48#include <linux/kernel.h>
49#include <linux/cleanup.h>
50/*
51 * linux/kthread.h (drm_vblank_work.c) includes this header and nothing
52 * else, and mainline's sched.h is wide enough to already carry all of
53 * this: the lock types and class key its worker API names, NUMA_NO_NODE
54 * for kthread_create_worker, and forward declarations so `const struct
55 * cpumask *` parameters do not get prototype-scope tags. timer/list/
56 * memset come through kernel.h above.
57 */
58#include <linux/spinlock.h> /* raw_spinlock_t in struct kthread_worker */
59#include <linux/lockdep.h> /* lock_class_key in kthread_init_worker */
60#include <linux/nodemask_types.h> /* NUMA_NO_NODE -- the type header, not
61 * nodemask.h: the bitmap API it carries is
62 * nothing this header uses */
63
64/*
65 * <linux/pid.h> -- task_tgid() and task_pid_nr(), the two task-identity
66 * accessors drm_auth.c:236 and drm_ioctl.c:883/:922/:930 call on `current`.
67 * mainline's fs.h carries pid.h and DCL's file.h does the same (file.h:68),
68 * but neither drm file includes file.h, so without it here those calls were
69 * implicit declarations -- permitted by the build's
70 * -Wno-implicit-function-declaration -- and surfaced at link time as
71 * undefined task_tgid (drm_auth.o) and task_pid_nr (drm_ioctl.o).
72 *
73 * Riding on sched.h is safe in either include order, which is what the two
74 * headers have to agree on: pid.h includes nothing, so no cycle back to this
75 * file is possible, and its own guard makes the include a no-op in the drm
76 * files that get it from file.h. The accessors are static inlines over
77 * forward-declared types (pid.h:25-26), so no struct is needed before this
78 * point either.
79 */
80#include <linux/pid.h>
81
82struct cpumask;
83
84#define TASK_RUNNING 0
85#define TASK_INTERRUPTIBLE 1
86#define TASK_UNINTERRUPTIBLE 2
87#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
88#define TASK_WAKEKILL 4
89#define __TASK_STOPPED 8
90#define TASK_PARKED 16
91
92/* Nothing ever waits this long, because nothing ever really waits at all. */
93#define MAX_SCHEDULE_TIMEOUT ((long)(~0UL >> 1))
94
95/*
96 * PF_KTHREAD / ->worker_private: tsk_is_kthread() in <linux/kthread.h>
97 * tests both, and kthread_create_worker() publishes the worker on the
98 * creating (kernel) task. DCL's task is the one shared task (see below),
99 * so the flag starts set -- every DCL thread is a kernel thread -- and
100 * worker_private is the slot kthread.h expects it to live in.
101 */
102#define PF_KTHREAD 0x00200000U
103
104struct tty_struct;
105struct task_struct;
106
109};
110
111/*
112 * mainline spells this as an enum (sched.h:325) so BPF can see it; DCL has
113 * no BPF, but the spelling is what drm_device.h:48 reaches for when it sizes
114 * the wedge task's `comm`, and sizing task_struct's own below with the same
115 * name keeps the two from drifting apart.
116 */
117enum {
119};
120
123 int pid;
125 unsigned int flags; /* PF_* -- PF_KTHREAD is set (see above) */
126 void* worker_private; /* kthread.h: struct kthread * owner */
127};
128
129/*
130 * The one DCL task. It is shared rather than per-thread: `current` is read
131 * for its `comm` (two deprecation warnings) and its `signal->tty` (one
132 * permission gate), never written by any of the nine files, so a single
133 * context whose `comm` is refreshed on each read answers truthfully without
134 * a task table that nothing else needs.
135 */
137/*
138 * #undef first: <linux/mm.h> carries a fallback `current ((void*)0)` for the
139 * headers that need the name without a scheduler. Which of the two lands
140 * second depends on the include order of the translation unit, and an
141 * unconditional redefinition is a -Wmacro-redefined warning at best and, at
142 * worst, `((void*)0)->comm` if mm.h wins. Redefining unconditionally is the
143 * right behaviour -- dcl_current() is the true one and mm.h's is only ever a
144 * fallback -- so drop whatever is there and put this one in, in both orders.
145 */
146#undef current
147#define current (dcl_current())
148
149/*
150 * task_pid_vnr() -- drm_ioctl.c:199's drm_getclient() stores it into
151 * struct drm_client and hands that back to userspace.
152 *
153 * mainline answers "the task's pid as current's namespace sees it"; DCL has
154 * no pid table, and <linux/pid.h> records what follows from that for the
155 * accessors it owns (task_tgid() is NULL, task_pid_nr() is 0 for a debug line
156 * whose text is compiled away). A value userspace reads back is the other
157 * case, and the task is not anonymous: dcl_current() refreshes ->pid from the
158 * running Xeneva thread on every call (DCL/current_ident.c), so that real
159 * thread id is what this reports. The NULL arm cannot come from any caller
160 * (they all pass `current`); 0 is the one answer that touches nothing.
161 *
162 * A static inline in the shape of pid.h's accessors rather than a shim
163 * symbol, for the same reason those are: the body is one field read, and a
164 * link symbol for it would be a call to a function a header could have
165 * compiled away.
166 */
167static inline int task_pid_vnr(struct task_struct* tsk)
168{
169 return tsk ? tsk->pid : 0;
170}
171
172/*
173 * get_task_comm(buf, tsk) -- mainline's accessor for a task's comm, which
174 * mainline also declares in <linux/sched.h> (there as a macro over
175 * __get_task_comm()). One caller, the virtio-gpu debug-name ioctl, and the
176 * copy is bounded by the struct's own `comm` array so the terminator
177 * always fits. `comm` is exactly what dcl_current() refreshes from the
178 * running thread on every call, so a live task's name is real text; the
179 * shape is this header's static-inline style rather than a shim symbol,
180 * for the task_pid_vnr() reason above.
181 */
182static inline char* get_task_comm(char* buf, struct task_struct* tsk)
183{
184 unsigned int i;
185
186 for (i = 0; i + 1 < sizeof(tsk->comm) && tsk->comm[i]; i++)
187 buf[i] = tsk->comm[i];
188 buf[i] = 0;
189 return buf;
190}
191
192void schedule(void);
193
194/*
195 * wake_up_process(tsk) -- tty_ldsem.c:97/:124/:245, where a waiter that has
196 * parked on the semaphore is told its turn came.
197 *
198 * mainline takes the task off the runqueue's sleep state and returns whether
199 * it found one. Here it returns 1 and does nothing else, and the reason it
200 * is safe for the semaphore to work at all is what schedule() is on this
201 * build: DCL/linux_irq_shim.c:350 parks in mdelay(1) and returns, so no task
202 * is ever *asleep* waiting for this -- the waiter in tty_ldsem.c's
203 * down_read_failed() loop re-evaluates its condition every millisecond
204 * whether or not anyone wakes it, and `wake_up_process` on a task that is
205 * already runnable is a no-op upstream too. A real wake-up would need a
206 * scheduler with a sleep state to wake out of.
207 *
208 * Returning 1 rather than void is mainline's signature: the callers discard
209 * it, but a decl that answered a different type would be a different symbol
210 * to a reader comparing this against tty_ldsem.c.
211 */
212static inline int wake_up_process(struct task_struct* tsk)
213{
214 (void)tsk;
215 return 1;
216}
217
218/*
219 * wake_up_state() -- dma-fence.c:796's dma_fence_default_wait_cb(), the
220 * callback a signaled fence runs to wake the task mainline parked in
221 * dma_fence_wait_timeout(). mainline's `state` names the sleep states the
222 * wake is allowed to clear; DCL's one task is never asleep, so there is no
223 * state to test against and the mask selects nothing.
224 *
225 * The 1 is wake_up_process()'s answer above and is chosen the same way: a
226 * caller that does read it gets "the wake was carried out" instead of a state
227 * test this kernel cannot make. dma_fence_default_wait_cb() discards it, and
228 * the wait the callback serves is the bounded one dma_fence_wait_timeout()
229 * runs, not a sleep this could end early.
230 */
231static inline int wake_up_state(struct task_struct* tsk, unsigned int state)
232{
233 (void)tsk;
234 (void)state;
235 return 1;
236}
237
238long schedule_timeout(long timeout);
239long schedule_timeout_killable(long timeout);
240
241#define set_current_state(s) do { (void)(s); } while (0)
242#define __set_current_state(s) do { (void)(s); } while (0)
243#define set_task_state(t, s) do { (void)(t); (void)(s); } while (0)
244#define __set_task_state(t, s) do { (void)(t); (void)(s); } while (0)
245
246/*
247 * signal_pending() -- always 0; Xeneva has no signals (see the definition in
248 * DCL/linux_irq_shim.c, which returns 0 and records the consequence for
249 * uart_wait_modem_status()).
250 *
251 * The declaration is guarded, and the reason is worth writing down because it
252 * is invisible from either side: <linux/mm.h> also provides this name, as a
253 * macro -- `#define signal_pending(p) 0` -- and in a translation unit where
254 * mm.h arrives first (DCL/linux_mm_shim.c includes it at line 32, then
255 * <linux/tty.h> at line 36, which reaches this file through tty_ldisc.h ->
256 * wait.h), an unguarded `int signal_pending(struct task_struct* tsk);` is
257 * expanded into `int 0(struct task_struct* tsk);` and clang reports
258 * "expected identifier or '('" at this line with no mention of the macro that
259 * did it. Guarding means: mm.h first, take its macro; this file first, take
260 * the declaration. Either order compiles, and both answer the same value.
261 */
262#ifndef signal_pending
264#endif
266
267/*
268 * cond_resched() -- mainline declares it in this header and defines it in
269 * kernel/sched/core.c as a real preemption point.
270 *
271 * In DCL there is no preemption point to take, so it is the same no-op
272 * <linux/mm.h> already provides, spelled identically and guarded the same way
273 * so the two headers can be included in either order without a redefinition.
274 *
275 * It has to be visible from here rather than only from mm.h: tty_buffer.c
276 * calls it (line 509, inside the flush_to_ldisc loop -- mainline's "yield if
277 * the consumer has been running a while") and includes <linux/sched.h> but
278 * never <linux/mm.h>. Without this, the call became an implicit declaration
279 * -- the build flags permit those -- and surfaced as `lld-link: undefined
280 * symbol: cond_resched` at link time instead of an error at the call site.
281 */
282#ifndef cond_resched
283#define cond_resched() ((void)0)
284#endif
285
286/* tty_io.c:3046 -- the only task lock the tty core takes directly. */
287void task_lock(struct task_struct* p);
288void task_unlock(struct task_struct* p);
289
291
292
293/*
294 * schedule_timeout_interruptible() -- the declaration beside schedule_timeout
295 * (mainline has both in this header), one user: tty_port.c:596, the yield in
296 * the block_til_ready() loop.
297 *
298 * The body is in DCL/linux_irq_shim.c next to schedule_timeout()'s and simply
299 * calls it, because the distinction the suffix carries does not exist here:
300 * mainline's version differs only in that a SIGINT could end the wait early,
301 * and <linux/sched.h> records at the top of this file that signal_pending() is
302 * always 0. With nothing to be interrupted by, two implementations would be
303 * two copies of one behaviour -- and one that let them disagree would be a
304 * caller waiting on a timeout the other had already clamped.
305 */
306long schedule_timeout_interruptible(long timeout);
307#endif /* __LINUX_SCHED_H__ */
#define DCL_LOCK_GUARD(name, type, acquire, release)
Definition cleanup.h:168
void task_lock(struct task_struct *p)
long schedule_timeout_killable(long timeout)
long schedule_timeout(long timeout)
void task_unlock(struct task_struct *p)
int fatal_signal_pending(struct task_struct *tsk)
void schedule(void)
@ TASK_COMM_LEN
Definition sched.h:118
struct task_struct * dcl_current(void)
#define signal_pending(p)
Definition mm.h:87
Definition sched.h:107
struct tty_struct * tty
Definition sched.h:108
Definition sched.h:121
unsigned int flags
Definition sched.h:125
void * worker_private
Definition sched.h:126
char comm[TASK_COMM_LEN]
Definition sched.h:122
int pid
Definition sched.h:123
struct signal_struct * signal
Definition sched.h:124
Definition tty.h:203
#define state(x)