Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / kernel / task.c
1 #include <lwk/kernel.h>
2 #include <lwk/xcall.h>
3 #include <lwk/htable.h>
4 #include <lwk/aspace.h>
5 #include <lwk/task.h>
6 #include <lwk/sched.h>
7 #include <arch/uaccess.h>
8
9 /**
10  * ID space used to allocate task IDs.
11  */
12 static idspace_t idspace;
13
14 /**
15  * Hash table used to lookup task structures by ID.
16  */
17 static htable_t htable;
18
19 /**
20  * Lock for serializing access to the htable.
21  */
22 static DEFINE_SPINLOCK(htable_lock);
23
24 int __init
25 task_subsys_init(void)
26 {
27         if (idspace_create(__TASK_MIN_ID, __TASK_MAX_ID, &idspace))
28                 panic("Failed to create task ID space.");
29
30         if (htable_create(7 /* 2^7 bins */,
31                           offsetof(struct task_struct, id),
32                           offsetof(struct task_struct, ht_link),
33                           &htable))
34                 panic("Failed to create task hash table.");
35
36         return 0;
37 }
38
39 int
40 task_get_myid(id_t *id)
41 {
42         *id = current->id;
43         return 0;
44 }
45
46 int
47 sys_task_get_myid(id_t __user *id)
48 {
49         int status;
50         id_t _id;
51
52         if ((status = task_get_myid(&_id)) != 0)
53                 return status;
54
55         if (id && copy_to_user(id, &_id, sizeof(*id)))
56                 return -EINVAL;
57
58         return 0;
59 }
60
61 int
62 __task_reserve_id(id_t id)
63 {
64         return idspace_alloc_id(idspace, id, NULL);
65 }
66
67 int
68 __task_create(id_t id, const char *name,
69               const start_state_t *start_state,
70               struct task_struct **task)
71 {
72         int status;
73         union task_union *task_union;
74         struct task_struct *tsk;
75
76         if ((task_union = kmem_get_pages(TASK_ORDER)) == NULL)
77                 return -ENOMEM;
78
79         tsk = &task_union->task_info;
80
81         /*
82          * Initialize the new task. kmem_alloc() allocates zeroed memory
83          * so fields with an initial state of zero do not need to be explicitly
84          * initialized.
85          */
86         tsk->id = id;
87         if (name)
88                 strlcpy(tsk->name, name, sizeof(tsk->name));
89         hlist_node_init(&tsk->ht_link);
90         tsk->state = TASKSTATE_READY;
91         tsk->uid = start_state->uid;
92         tsk->gid = start_state->gid;
93         tsk->aspace = aspace_acquire(start_state->aspace_id);
94         if (!tsk->aspace) {
95                 status = -ENOENT;
96                 goto error1;
97         }
98         tsk->sighand = NULL;
99         if (start_state->cpumask) {
100                 cpumask_user2kernel(start_state->cpumask, &tsk->cpumask);
101                 if (!cpus_subset(tsk->cpumask, current->cpumask)) {
102                         status = -EINVAL;
103                         goto error2;
104                 }
105         } else {
106                 tsk->cpumask = current->cpumask;
107         }
108         if ((start_state->cpu_id >= NR_CPUS)
109              || !cpu_isset(start_state->cpu_id, tsk->cpumask)) {
110                 status = -EINVAL;
111                 goto error2;
112         }
113         tsk->cpu_id = start_state->cpu_id;
114         list_head_init(&tsk->sched_link);
115         tsk->ptrace = 0;
116         tsk->flags = 0;
117         tsk->exit_status = 0;
118
119         /* Do architecture-specific initialization */
120         if ((status = arch_task_create(tsk, start_state)) != 0)
121                 goto error2;
122
123         if (task)
124                 *task = tsk;
125         return 0;
126
127 error2:
128         if (tsk->aspace)
129                 aspace_release(tsk->aspace);
130 error1:
131         kmem_free_pages(task_union, TASK_ORDER);
132         return status;
133 }
134
135 int
136 task_create(id_t id_request, const char *name,
137             const start_state_t *start_state, id_t *id)
138 {
139         id_t new_id;
140         struct task_struct *new_task;
141         int status;
142         unsigned long irqstate;
143
144         /* Allocate an ID for the new task */
145         if ((status = idspace_alloc_id(idspace, id_request, &new_id)) != 0)
146                 return status;
147
148         /* Create and initialize a new task */
149         if ((status = __task_create(new_id, name, start_state, &new_task))) {
150                 idspace_free_id(idspace, new_id);
151                 return status;
152         }
153
154         /* Add new task to a hash table, for quick lookups by ID */
155         spin_lock_irqsave(&htable_lock, irqstate);
156         BUG_ON(htable_add(htable, new_task));
157         spin_unlock_irqrestore(&htable_lock, irqstate);
158
159         /* Add the new task to the target CPU's run queue */
160         sched_add_task(new_task);
161
162         if (id)
163                 *id = new_task->id;
164         return 0;
165 }
166
167 int
168 sys_task_create(id_t id_request, const char __user *name,
169                 const start_state_t __user *start_state, id_t __user *id)
170 {
171         int status;
172         start_state_t _start_state;
173         user_cpumask_t _cpumask;
174         char _name[16];
175         id_t _id;
176
177         if (current->uid != 0)
178                 return -EPERM;
179
180         if (copy_from_user(&_start_state, start_state, sizeof(_start_state)))
181                 return -EINVAL;
182
183         if (_start_state.aspace_id == KERNEL_ASPACE_ID)
184                 return -EINVAL;
185
186         if (_start_state.cpumask) {
187                 if (copy_from_user(&_cpumask, _start_state.cpumask, sizeof(_cpumask)))
188                         return -EINVAL;
189                 _start_state.cpumask = &_cpumask;
190         }
191
192         if (name && (strncpy_from_user(_name, name, sizeof(_name)) < 0))
193                 return -EFAULT;
194         _name[sizeof(_name) - 1] = '\0';
195
196         if ((status = task_create(id_request, _name, &_start_state, &_id)) != 0)
197                 return status;
198
199         if (id && copy_to_user(id, &_id, sizeof(*id)))
200                 return -EFAULT;
201
202         return 0;
203 }
204
205 int
206 task_exit(int status)
207 {
208         /* Mark the task as exited...
209          * schedule() will remove it from the run queue */
210         current->exit_status = status;
211         current->state = TASKSTATE_EXIT_ZOMBIE;
212         schedule(); /* task is dead, so this should never return */
213         BUG();
214         while (1) {}
215 }
216
217 int
218 sys_task_exit(int status)
219 {
220         return task_exit(status);
221 }
222
223 int
224 task_yield(void)
225 {
226         /*
227          * Nothing to do, schedule() will be automatically
228          * called before returning to user-space
229          */
230         return 0;
231 }
232
233 int
234 sys_task_yield(void)
235 {
236         return task_yield();
237 }