New developer version 0.6.8; added select () function; added demonstrating example...
[ZeXOS.git] / kernel / core / sched.c
blobf2f2eb2ff02fa57b8ba21e533889c9b1f803a5bc
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
6 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <build.h>
24 #include <system.h>
25 #include <arch/io.h>
26 #include <string.h>
27 #include <setjmp.h>
28 #include <task.h>
29 #include <spinlock.h>
31 task_t task_list;
32 task_t *_curr_task;
33 extern unsigned long timer_ticks;
35 unsigned task_id = NULL;
37 SPINLOCK_CREATE (sched_spinlock);
40 /** SCHEDULE
41 * Function, which handle each task.
42 * It jump from task to another task in moment, when schedule () is called.
45 void schedule (void)
47 /* avoid for crash */
48 if (!_curr_task)
49 return;
51 if (_curr_task->spinlock)
52 if (_curr_task->spinlock->locked)
53 return;
55 /* we dont need check spinlock now, because we check it below,
56 when we are sure about running task */
57 spinlock_lock (&sched_spinlock);
59 /* check task with priority > 0 */
60 if (_curr_task->priority) { /* is it on kernel level ? No ? Let's continue */
61 _curr_task->attick ++;
63 _curr_task->lasttick = timer_ticks; /* remember current tick time */
64 #ifdef ARCH_i386
65 if (_curr_task->attick < 256/_curr_task->priority) /* calculate when process have to be block and when not */
66 return;
67 else
68 _curr_task->attick = 0; /* handle current task and null attick counter */
69 #else
70 /*if (_curr_task->attick < 256/_curr_task->priority)*/ /* calculate when process have to be block and when not */
71 // return;
72 /*else*/
73 _curr_task->attick = 0; /* handle current task and null attick counter */
74 #endif
77 /* set current task */
78 if (arch_task_set (_curr_task))
79 return;
81 for (;;) {
82 /* continue on next task */
83 _curr_task = _curr_task->next;
85 /* task is out of task_list structure */
86 if (_curr_task == &task_list)
87 _curr_task = task_list.next; /* current task is first task in task_list structure */
89 /* Is current task running ? */
90 if (_curr_task->status == TS_RUNNABLE) {
91 #ifdef ARCH_i386
92 /* switch page directory for current task */
93 if (_curr_task->page_cover)
94 page_dir_switch (_curr_task->page_cover->page_dir);
95 else /* when page_cover pointer is NULL, it mean that kernel task is current */
96 page_dir_switch (task_list.next->page_cover->page_dir);
97 #endif
98 if (!int_disable ())
99 return;
101 if (_curr_task->spinlock)
102 if (_curr_task->spinlock->locked)
103 spinlock_unlock (&sched_spinlock);
106 /* switch to new/current task */
107 arch_task_switch (_curr_task);
109 return;
114 /*****************************************************************************
115 *****************************************************************************/
116 void task_schedule ()
118 for (;;)
119 schedule ();
122 extern unsigned short *vesafb;
123 extern unsigned char vgagui;
124 task_t *task_create (char *name, unsigned entry, unsigned priority)
126 if (priority > 255) /* priority 256 is max */
127 priority = 255;
129 /* alloc and init context */
130 task_t *task = (task_t *) kmalloc (sizeof (task_t));
132 /* out of memory ? */
133 if (!task) {
134 DPRINT (DBG_SCHED, "task_create () - !task");
135 task = (task_t *) kmalloc (sizeof (task_t));
137 if (!task)
138 return 0;
141 if (entry == NULL) {
142 /* mark task #0 (idle task) runnable */
143 task->status = TS_RUNNABLE;
145 task->priority = priority;
146 // add name of task
147 strcpy (task->name, name);
149 task->spinlock = &sched_spinlock;
151 task->id = task_id;
152 #ifdef ARCH_i386
153 task->page_cover = 0;
155 task->page_cover = (page_ent_t *) page_cover_create ();
157 /* kernel covering by paging */
158 page_mmap (task->page_cover, 0, (void *) PAGE_MEM_LOW, 1, 0);
160 /* framebuffer covering by paging */
161 page_mmap (task->page_cover, (void *) PAGE_MEM_LOW, (void *) PAGE_MEM_FB, 1, 1);
163 /* user-space covering by paging */
164 page_mmap (task->page_cover, (void *) PAGE_MEM_FB, (void *) PAGE_MEM_HIGH, 1, 0);
166 page_dir_switch (task->page_cover->page_dir);
168 paging_enable ();
169 #endif
170 /* add into list */
171 task->next = &task_list;
172 task->prev = task_list.prev;
173 task->prev->next = task;
174 task->next->prev = task;
176 /* set _curr_task so schedule() will save state of task #0 */
177 _curr_task = task;
178 #ifdef ARCH_arm
179 /* NOTE: ARM need to start new fake of main kernel task */
180 arch_task_init (task, (unsigned) &task_schedule);
181 #endif
182 return task;
185 arch_task_init (task, entry);
187 task_id ++; // increase id number for new task
189 // mark it runnable
190 task->status = TS_RUNNABLE;
191 // task priority - how offten will be active
192 task->priority = priority;
193 // task attick - how ofter per all time line handle this task (not in %)
194 task->attick = task_id - 1;
195 // add name of task
196 strcpy (task->name, name);
197 // spinlock is not available by default
198 task->spinlock = 0;
199 // page covering of process
200 task->page_cover = 0;
201 // task identification number - usefully on process level (multi-threaded apps)
202 task->id = task_id;
203 // task's time stamp of last tick
204 task->lasttick = 0;
206 /* add into list */
207 task->next = &task_list;
208 task->prev = task_list.prev;
209 task->prev->next = task;
210 task->next->prev = task;
212 DPRINT (DBG_SCHED, "task -> %s (%d)", name, task_id);
214 return task;
217 bool task_done (task_t *task)
219 if (task) {
220 DPRINT (DBG_SCHED, "task -> %s done", task->name);
222 task->status = TS_NULL;
224 task->next->prev = task->prev;
225 task->prev->next = task->next;
227 kfree (task);
229 return 1;
232 return 0;
235 task_t *task_find (unsigned short id)
237 task_t *task;
238 for (task = task_list.next; task != &task_list; task = task->next) {
239 if (task->id == id)
240 return task;
243 return 0;
246 unsigned int init_tasks (void)
248 task_list.next = &task_list;
249 task_list.prev = &task_list;
251 /* NOTE: NULL entry point task can't be created multiple times ! */
252 task_create ("kernel", NULL, 0);
254 return 1;