summaryrefslogtreecommitdiff
path: root/src/kernel/proc.h
blob: 512077898519adddc5e7a02889beb8e708d03507 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#pragma once
#include <kernel/arch/generic.h>
#include <kernel/handle.h>
#include <kernel/types.h>
#include <stdbool.h>

#define HANDLE_MAX 16

/* legal transitions described by proc_setstate */
enum proc_state {
	PS_RUNNING,
	PS_DYING, /* during proc_kill - mostly treated as alive */
	PS_TOREAP, /* return message not collected */
	PS_TOMBSTONE, /* fully dead, supports alive children */
	/* not in the process tree, waits for free.
	 * *sibling holds a linked list of all the FORGOTTEN processes */
	PS_FORGOTTEN,
	PS_FREED, /* only meant to detect double frees */

	PS_WAITS4CHILDDEATH,
	PS_WAITS4FS,
	PS_WAITS4REQUEST,
	PS_WAITS4PIPE,
	PS_WAITS4TIMER,

	PS_LAST,
};

#define proc_alive(p) (p \
		&& p->state != PS_TOREAP \
		&& p->state != PS_TOMBSTONE \
		&& p->state != PS_FORGOTTEN \
		&& p->state != PS_FREED \
		)

struct Proc {
	Pagedir *pages;
	/* if NULL, refcount == 1. kmalloc'd */
	uint64_t *pages_refcount;

	CpuRegs regs;
	Proc *sibling, *child, *parent;

	enum proc_state state;
	union { /* saved value, meaning depends on .state */
		int death_msg; // PS_DEAD
		struct {
			char __user *buf;
			size_t max_len;
			struct ufs_request __user *res;
		} awaited_req; // PS_WAITS4REQUEST
		struct {
			Handle *pipe;
			char __user *buf;
			size_t len;
			Proc *next;
		} waits4pipe;
		struct {
			/* managed by timer_schedule */
			uint64_t goal;
			Proc *next;
		} waits4timer;
	};

	VfsMount *mount;
	Handle **_handles; /* points to Handle *[HANDLE_MAX] */
	uint64_t *handles_refcount; /* works just like pages_refcount */
	struct {
		Handle *procfs;
	} specialh;

	uint32_t cid; /* child id. unique amongst all of this process' siblings */
	uint32_t nextcid; /* the child id to assign to the next spawned child */
	uint32_t globalid; /* only for internal use, don't expose to userland */
	uint32_t refcount; /* non-owning. should always be 0 on kill */
	bool noreap;

	/* allocated once, the requests from WAITS4FS get stored here */
	VfsReq *reqslot;

	/* vfs_backend controlled (not exclusively) by this process */
	VfsBackend *controlled;

	/* interrupt handler */
	void __user *intr_fn;

	struct {
		void *buf;
		size_t len;
		size_t pos;
	} execbuf;
};

extern Proc *proc_cur;

/** Creates the root process. */
Proc *proc_seed(void *data, size_t datalen);
Proc *proc_fork(Proc *parent, int flags);

void proc_kill(Proc *proc, int ret);
/** Kills all descendants. */
void proc_filicide(Proc *proc, int ret);
/** Tries to reap a dead process / free a tombstone. */
void proc_tryreap(Proc *dead);

void proc_intr(Proc *proc);

/** Switches execution to any running process. */
_Noreturn void proc_switch_any(void);

/** Used for iterating over all processes */
Proc *proc_next(Proc *p, Proc *root);

hid_t proc_find_free_handle(Proc *proc, hid_t start_at);
Handle *proc_handle_get(Proc *, hid_t);
hid_t proc_handle_init(Proc *, enum handle_type, Handle **);
hid_t proc_handle_dup(Proc *p, hid_t from, hid_t to);
static inline void proc_handle_close(Proc *p, hid_t hid) {
	// TODO test
	proc_handle_dup(p, -1, hid);
}

/* Gets a handle and removes the process' reference to it, without decreasing the refcount.
 * Meant to be used together with proc_handle_put. */
Handle *proc_hid_take(Proc *, hid_t);
/* Put a handle in a process, taking the ownership away from the caller.
 * Doesn't increase the refcount on success, decreases it on failure. */
hid_t proc_handle_put(Proc *, Handle *);

void proc_setstate(Proc *, enum proc_state);