Version 0.6.7: Added support for hostname - hostname_get (), hostname_set (); Hostnam...
[ZeXOS.git] / kernel / core / sched.c
blob39f1976882f7db4267c80dc70761caf7ab0d07c0
1 /*
2 * ZeX/OS
3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <build.h>
23 #include <system.h>
24 #include <arch/io.h>
25 #include <string.h>
26 #include <setjmp.h>
27 #include <task.h>
28 #include <spinlock.h>
30 task_t task_list;
31 task_t *_curr_task;
32 extern unsigned long timer_ticks;
34 unsigned task_id = NULL;
36 SPINLOCK_CREATE (sched_spinlock);
39 /** SCHEDULE
40 * Function, which handle each task.
41 * It jump from task to another task in moment, when schedule () is called.
44 void schedule (void)
46 /* avoid for crash */
47 if (!_curr_task)
48 return;
50 if (_curr_task->spinlock)
51 if (_curr_task->spinlock->locked)
52 return;
54 /* we dont need check spinlock now, because we check it below,
55 when we are sure about running task */
56 spinlock_lock (&sched_spinlock);
58 /* check task with priority > 0 */
59 if (_curr_task->priority) { /* is it on kernel level ? No ? Let's continue */
60 _curr_task->attick ++;
62 _curr_task->lasttick = timer_ticks; /* remember current tick time */
63 #ifdef ARCH_i386
64 if (_curr_task->attick < 256/_curr_task->priority) /* calculate when process have to be block and when not */
65 return;
66 else
67 _curr_task->attick = 0; /* handle current task and null attick counter */
68 #else
69 /*if (_curr_task->attick < 256/_curr_task->priority)*/ /* calculate when process have to be block and when not */
70 // return;
71 /*else*/
72 _curr_task->attick = 0; /* handle current task and null attick counter */
73 #endif
74 } else /* we dont need use everytime 100% of cpu time - wait a tick */
75 arch_cpu_hlt ();
77 /* set current task */
78 if (arch_task_set (_curr_task))
79 return;
82 for (;;) {
83 /* continue on next task */
84 _curr_task = _curr_task->next;
86 /* task is out of task_list structure */
87 if (_curr_task == &task_list)
88 _curr_task = task_list.next; /* current task is first task in task_list structure */
90 /* Is current task running ? */
91 if (_curr_task->status == TS_RUNNABLE) {
92 #ifdef ARCH_i386
93 /* switch page directory for current task */
94 if (_curr_task->page_cover)
95 page_dir_switch (_curr_task->page_cover->page_dir);
96 else /* when page_cover pointer is NULL, it mean that kernel task is current */
97 page_dir_switch (task_list.next->page_cover->page_dir);
98 #endif
99 if (!int_disable ())
100 return;
102 if (_curr_task->spinlock)
103 if (_curr_task->spinlock->locked)
104 spinlock_unlock (&sched_spinlock);
107 /* switch to new/current task */
108 arch_task_switch (_curr_task);
110 return;
115 /*****************************************************************************
116 *****************************************************************************/
117 void task_schedule ()
119 for (;;)
120 schedule ();
123 extern unsigned short *vesafb;
124 extern unsigned char vgagui;
125 task_t *task_create (char *name, unsigned entry, unsigned priority)
127 if (priority > 255) /* priority 256 is max */
128 priority = 255;
130 /* alloc and init context */
131 task_t *task = (task_t *) kmalloc (sizeof (task_t));
133 /* out of memory ? */
134 if (!task) {
135 DPRINT (DBG_SCHED, "task_create () - !task");
136 task = (task_t *) kmalloc (sizeof (task_t));
138 if (!task)
139 return 0;
142 if (entry == NULL) {
143 /* mark task #0 (idle task) runnable */
144 task->status = TS_RUNNABLE;
146 task->priority = priority;
147 // add name of task
148 strcpy (task->name, name);
150 task->spinlock = &sched_spinlock;
152 task->id = task_id;
153 #ifdef ARCH_i386
154 task->page_cover = 0;
156 task->page_cover = (page_ent_t *) page_cover_create ();
158 /* kernel covering by paging */
159 page_mmap (task->page_cover, 0, (void *) 0x400000, 1, 0);
161 /* framebuffer covering by paging */
162 page_mmap (task->page_cover, (void *) 0x400000, (void *) 0x500000, 1, 1);
164 /* user-space covering by paging */
165 page_mmap (task->page_cover, (void *) 0x500000, (void *) 0x800000, 1, 0);
167 //if (vgagui == 2)
168 // page_mmap (task->page_cover, (void *) vesafb, (void *) ((void *) vesafb+(800*600*4)), 1, 0);
169 /*if (vgagui == 2) {
170 page_mmap (task->page_cover, (void *) PAGE_MEM_LOW, (void *) ((void *) PAGE_MEM_LOW+0x100000+800*600*vgagui), 1, 1);
172 //vesafb = (void *) PAGE_MEM_LOW;
175 page_dir_switch (task->page_cover->page_dir);
176 //if (vgagui != 2) {
177 paging_enable ();
179 /* unsigned p = 0;
180 for (p = 0; p < 800*600; p ++)
181 vesafb[p] = ~0;*/
183 #endif
184 /* add into list */
185 task->next = &task_list;
186 task->prev = task_list.prev;
187 task->prev->next = task;
188 task->next->prev = task;
190 /* set _curr_task so schedule() will save state of task #0 */
191 _curr_task = task;
192 #ifdef ARCH_arm
193 /* NOTE: ARM need to start new fake of main kernel task */
194 arch_task_init (task, (unsigned) &task_schedule);
195 #endif
196 return task;
199 arch_task_init (task, entry);
201 task_id ++; // increase id number for new task
203 // mark it runnable
204 task->status = TS_RUNNABLE;
205 // task priority - how offten will be active
206 task->priority = priority;
207 // task attick - how ofter per all time line handle this task (not in %)
208 task->attick = task_id - 1;
209 // add name of task
210 strcpy (task->name, name);
211 // spinlock is not available by default
212 task->spinlock = 0;
213 // page covering of process
214 task->page_cover = 0;
215 // task identification number - usefully on process level (multi-threaded apps)
216 task->id = task_id;
217 // task's time stamp of last tick
218 task->lasttick = 0;
220 /* add into list */
221 task->next = &task_list;
222 task->prev = task_list.prev;
223 task->prev->next = task;
224 task->next->prev = task;
226 DPRINT (DBG_SCHED, "task -> %s (%d)", name, task_id);
228 return task;
231 bool task_done (task_t *task)
233 if (task) {
234 DPRINT (DBG_SCHED, "task -> %s done", task->name);
236 task->status = TS_NULL;
238 task->next->prev = task->prev;
239 task->prev->next = task->next;
241 kfree (task);
243 return 1;
246 return 0;
249 task_t *task_find (unsigned short id)
251 task_t *task;
252 for (task = task_list.next; task != &task_list; task = task->next) {
253 if (task->id == id)
254 return task;
257 return 0;
260 unsigned int init_tasks (void)
262 task_list.next = &task_list;
263 task_list.prev = &task_list;
265 /* NOTE: NULL entry point task can't be created multiple times ! */
266 task_create ("kernel", NULL, 0);
268 return 1;