summaryrefslogtreecommitdiff
path: root/Kernel/Task.h
blob: c5a1362d14838bde9da1b4a55d71cdaa97635e92 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#pragma once

#include "types.h"
#include "InlineLinkedList.h"
#include <AK/String.h>
#include "TSS.h"
#include <AK/Vector.h>
#include "i386.h"
#include <VirtualFileSystem/VirtualFileSystem.h>

//#define TASK_SANITY_CHECKS

class FileHandle;
class Zone;

class Task : public InlineLinkedListNode<Task> {
    friend class InlineLinkedListNode<Task>;
public:
    static Task* createKernelTask(void (*entry)(), String&& name);
    static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr);
    ~Task();

    static Vector<Task*> allTasks();

#ifdef TASK_SANITY_CHECKS
    static void checkSanity(const char* msg = nullptr);
#else
    static void checkSanity(const char*) { }
#endif

    enum State {
        Invalid = 0,
        Runnable = 1,
        Running = 2,
        Terminated = 3,
        Crashing = 4,
        Exiting = 5,
        BlockedSleep = 6,
        BlockedWait = 7,
        BlockedRead = 8,
    };

    enum RingLevel {
        Ring0 = 0,
        Ring3 = 3,
    };

    bool isRing0() const { return m_ring == Ring0; }
    bool isRing3() const { return m_ring == Ring3; }

    static Task* fromPID(pid_t);
    static Task* kernelTask();

    const String& name() const { return m_name; }
    pid_t pid() const { return m_pid; }
    DWORD ticks() const { return m_ticks; }
    WORD selector() const { return m_farPtr.selector; }
    TSS32& tss() { return m_tss; }
    State state() const { return m_state; }
    uid_t uid() const { return m_uid; }
    uid_t gid() const { return m_gid; }

    pid_t parentPID() const { return m_parentPID; }

    const FarPtr& farPtr() const { return m_farPtr; }

    FileHandle* fileHandleIfExists(int fd);

    static void doHouseKeeping();

    void block(Task::State);
    void unblock();

    void setWakeupTime(DWORD t) { m_wakeupTime = t; }
    DWORD wakeupTime() const { return m_wakeupTime; }

    static void prepForIRETToNewTask();

    bool tick() { ++m_ticks; return --m_ticksLeft; }
    void setTicksLeft(DWORD t) { m_ticksLeft = t; }

    void setSelector(WORD s) { m_farPtr.selector = s; }
    void setState(State s) { m_state = s; }

    uid_t sys$getuid();
    gid_t sys$getgid();
    pid_t sys$getpid();
    int sys$open(const char* path, size_t pathLength);
    int sys$close(int fd);
    int sys$read(int fd, void* outbuf, size_t nread);
    int sys$lstat(const char*, void* statbuf);
    int sys$seek(int fd, int offset);
    int sys$kill(pid_t pid, int sig);
    int sys$geterror() { return m_error; }
    void sys$exit(int status);
    int sys$spawn(const char* path, const char** args);
    pid_t sys$waitpid(pid_t);
    void* sys$mmap(void*, size_t size);
    int sys$munmap(void*, size_t size);
    int sys$get_dir_entries(int fd, void*, size_t);
    int sys$getcwd(char*, size_t);
    int sys$chdir(const char*);
    int sys$sleep(unsigned seconds);
    int sys$gettimeofday(timeval*);
    int sys$gethostname(char* name, size_t length);
    int sys$get_arguments(int* argc, char*** argv);

    static void initialize();

    static void taskDidCrash(Task*);

    void dumpRegions();

    void didSchedule() { ++m_timesScheduled; }
    dword timesScheduled() const { return m_timesScheduled; }

    pid_t waitee() const { return m_waitee; }

    size_t fileHandleCount() const { return m_fileHandles.size(); }

private:
    friend class MemoryManager;
    friend bool scheduleNewTask();

    Task(String&& name, uid_t, gid_t, pid_t parentPID, RingLevel);

    void allocateLDT();

    Task* m_prev { nullptr };
    Task* m_next { nullptr };

    String m_name;
    void (*m_entry)() { nullptr };
    pid_t m_pid { 0 };
    uid_t m_uid { 0 };
    gid_t m_gid { 0 };
    DWORD m_ticks { 0 };
    DWORD m_ticksLeft { 0 };
    DWORD m_stackTop { 0 };
    FarPtr m_farPtr;
    State m_state { Invalid };
    DWORD m_wakeupTime { 0 };
    TSS32 m_tss;
    Descriptor* m_ldtEntries { nullptr };
    Vector<OwnPtr<FileHandle>> m_fileHandles;
    RingLevel m_ring { Ring0 };
    int m_error { 0 };
    void* m_kernelStack { nullptr };
    dword m_timesScheduled { 0 };
    pid_t m_waitee { -1 };
    int m_fdBlockedOnRead { -1 };
    size_t m_maxFileHandles { 16 };

    RetainPtr<VirtualFileSystem::Node> m_cwd;

    struct Region {
        Region(LinearAddress, size_t, RetainPtr<Zone>&&, String&&);
        ~Region();
        LinearAddress linearAddress;
        size_t size { 0 };
        RetainPtr<Zone> zone;
        String name;
    };
    Region* allocateRegion(size_t, String&& name);
    bool deallocateRegion(Region& region);

    Region* regionFromRange(LinearAddress, size_t);

    Vector<OwnPtr<Region>> m_regions;

    // FIXME: Implement some kind of ASLR?
    LinearAddress m_nextRegion;

    pid_t m_parentPID { 0 };

    Vector<String> m_arguments;
};

extern void task_init();
extern void yield();
extern bool scheduleNewTask();
extern void switchNow();
extern void block(Task::State);
extern void sleep(DWORD ticks);

/* The currently executing task. NULL during kernel bootup. */
extern Task* current;