New version 0.6.6: app edit was improved; app nc was improved + code cleanup; app...
[ZeXOS.git] / kernel / core / proc.c
blob54528e41c0229cad424de2ed69774e21fa6be576
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 <system.h>
23 #include <string.h>
24 #include <proc.h>
25 #include <tty.h>
26 #include <task.h>
27 #include <signal.h>
28 #include <build.h>
29 #include <paging.h>
30 #include <vfs.h>
31 #include <net/socket.h>
32 #include <fd.h>
34 pid_t newpid = 0;
36 proc_t proc_list;
37 proc_t proc_kernel;
39 extern task_t task_list;
40 extern task_t *_curr_task;
41 extern unsigned long timer_ticks;
43 pid_t fork ()
45 proc_t *p = proc_find (_curr_task);
47 if (!p)
48 return 0;
50 #ifdef ARCH_i386
51 return proc_create (p->tty, p->name, p->task->state[0].JMPBUF_IP)->pid;
52 #endif
55 void proc_display ()
57 printf ("PID\tCMD\tMEM\n");
59 proc_t *proc;
60 for (proc = proc_list.next; proc != &proc_list; proc = proc->next)
61 printf ("%d\t%s\t%dkB\n", proc->pid, proc->name, umem_used_proc (proc) / 1024);
64 void proc_top ()
66 tty_t *tty = currtty;
68 unsigned long ltime = 0;
70 for (;;) {
71 if (tty != currtty) {
72 schedule ();
73 continue;
76 tty_cls (tty);
78 printf ("TID\tTASK\t\tCPU Usage\n");
80 task_t *task;
81 for (task = task_list.next; task != &task_list; task = task->next) {
82 unsigned usage = 100 - ((task->lasttick - ltime) / 10);
83 char name[17];
84 memset (name, ' ', 16);
85 memcpy (name, task->name, strlen (task->name) > 16 ? 16 : strlen (task->name));
86 name[16] = '\0';
88 printf ("%d\t%s%d%%\n", task->id, name, usage > 100 ? 100 : usage);
89 schedule ();
93 proc_t *proc;
94 for (proc = proc_list.next; proc != &proc_list; proc = proc->next) {
95 printf ("\nPID\tCMD\t\tMEM\tCPU Usage\n");
96 break;
99 for (proc = proc_list.next; proc != &proc_list; proc = proc->next) {
100 schedule ();
101 unsigned usage = 100 - ((proc->task->lasttick - ltime) / 10);
102 char name[17];
103 memset (name, ' ', 16);
104 memcpy (name, proc->task->name, strlen (proc->task->name) > 16 ? 16 : strlen (proc->task->name));
105 name[16] = '\0';
106 printf ("%d\t%s%dkB\t%d%%\n", proc->pid, name, umem_used_proc (proc) / 1024, usage > 100 ? 100 : usage);
109 unsigned long stime = timer_ticks;
111 ltime = timer_ticks;
113 /* timeout for 1s */
114 while ((stime+1000) >= timer_ticks) {
115 if (getkey () == 'q')
116 return;
118 schedule ();
123 proc_t *proc_find (task_t *task)
125 proc_t *proc;
126 for (proc = proc_list.next; proc != &proc_list; proc = proc->next) {
127 if (!proc->task)
128 continue;
130 if (proc->task->id == task->id)
131 return proc;
134 return 0;
137 proc_t *proc_findbypid (pid_t pid)
139 proc_t *proc;
140 for (proc = proc_list.next; proc != &proc_list; proc = proc->next) {
141 if (proc->pid == pid)
142 return proc;
145 return 0;
148 unsigned proc_fd_close (proc_t *proc)
150 fd_t *f;
152 unsigned i;
154 while (1) {
155 i = 0;
156 for (f = fd_list.next; f != &fd_list; f = f->next) {
157 if (f->proc == proc) {
158 if (f->flags & FD_SOCK) // socket close
159 sclose (f->id);
161 fd_delete (f);
163 i ++;
164 break;
168 if (!i)
169 return 1;
172 return 0;
175 proc_t *proc_create (tty_t *tty, char *name, unsigned entry)
177 proc_t *proc = NULL;
178 task_t *task = (task_t *) task_create (name, entry, PROC_USER_PRIORITY);
180 if (!task) {
181 DPRINT ("proc_create () - !task");
182 return 0;
185 /* alloc and init context */
186 proc = (proc_t *) kmalloc (sizeof (proc_t));
188 if (!proc) {
189 DPRINT ("proc_create () - !proc");
190 return 0;
193 /* remember task, because we need it for scheduler work */
194 proc->task = task;
196 /* remember new pid of process */
197 proc->pid = ++ newpid;
199 /* remember tty, where we start this process */
200 proc->tty = tty;
202 /* setup process name */
203 strcpy (proc->name, name);
205 /* clear process info */
206 proc->start = 0;
207 proc->code = 0;
208 proc->data = 0;
209 proc->data_off = 0;
210 proc->bss = 0;
211 proc->end = 0;
213 proc->argc = 0;
214 proc->argv = 0;
216 proc->flags = 0;
218 /* add structure into process list */
219 proc->next = &proc_list;
220 proc->prev = proc_list.prev;
221 proc->prev->next = proc;
222 proc->next->prev = proc;
224 /* create virtual file in /proc with name of new process */
225 vfs_list_add (name, VFS_FILEATTR_FILE | VFS_FILEATTR_SYSTEM, "/proc/");
227 DPRINT ("proc -> %s, pid %d, entry 0x%x", name, newpid, entry);
229 return proc;
232 extern bool task_done (task_t *task);
233 bool proc_done (proc_t *proc)
235 if (proc) {
236 /* verify task structure */
237 if (!proc->task)
238 return 0;
239 #ifdef ARCH_i386
240 /* unmap memory pages */
241 proc_vmem_unmap (proc);
242 #endif
243 /* delete all tasks from process context */
244 unsigned short id = proc->task->id;
246 while (1) {
247 task_t *task = task_find (id);
249 if (!task)
250 break;
252 if (!task_done (task))
253 return 0;
256 DPRINT ("proc -> pid %d done", proc->pid);
258 /* close all un-closed file descriptors */
259 proc_fd_close (proc);
261 /* delete process from context */
262 proc->next->prev = proc->prev;
263 proc->prev->next = proc->next;
265 proc->task = 0;
267 /* free memory from process parameters */
268 proc_arg_free (proc);
270 /* free all memory blocks allocated by process */
271 ufree_proc (proc);
273 /* free process structure */
274 kfree (proc);
276 return 1;
279 return 0;
282 bool proc_signal (proc_t *proc, unsigned signal)
284 #ifdef ARCH_i386
285 if (!proc)
286 return 0;
288 /* check for daemon */
289 if (proc->flags & PROC_FLAG_DAEMON)
290 return 0;
292 task_t *task = proc->tty->task;
294 /* this unlock tty, enable itrs, etc (see command_exec ())*/
295 proc->pid = 0;
297 /* disable interrupts */
298 if (!int_disable ())
299 return 0;
301 /* jump back from app code to kernel code (task) */
302 longjmp (task->state, 1);
303 #else
304 DPRINT ("proc_signal: Not implemented for this platform !");
305 #endif
306 return 1;
309 sighandler_t signal (int signum, sighandler_t handler)
311 /* try to search current process */
312 proc_t *proc = proc_find (_curr_task);
314 if (!proc)
315 return 0;
317 if (proc->task != _curr_task)
318 return 0;
320 if (proc->tty != currtty)
321 return 0;
323 /* send signal to current process */
324 proc_signal (proc, signum);
326 return handler;
329 bool proc_arg_set (proc_t *proc, char *arg, unsigned argl)
331 if (!proc)
332 return 0;
334 unsigned i = 0;
335 unsigned y = 0;
336 unsigned x = 0;
338 if (proc->argc)
339 return 0;
341 /* First calculate length of array */
342 if (argl)
343 while (i < (argl+1)) {
344 if (arg[i] == ' ' || arg[i] == '\0')
345 x ++;
347 i ++;
350 proc->argv = (char **) kmalloc (sizeof (unsigned) * (x+2));
352 if (!proc->argv)
353 return 0;
355 proc->argc = x+1; /* +1 because argv[0] is name of process so it is one entry */
357 /* setup program name entry */
358 i = strlen (proc->name);
360 proc->argv[0] = (char *) kmalloc (sizeof (char) * (i+1));
361 memcpy (proc->argv[0], proc->name, i);
362 proc->argv[0][i] = '\0';
364 x = 1;
365 i = 0;
367 /* assign values to array */
368 while (i < (argl+1)) {
369 if (arg[i] == ' ' || arg[i] == '\0' || i == argl) {
370 if (!y) {
371 proc->argv[x] = (char *) kmalloc (sizeof (char) * (i+1));
373 if (!proc->argv[x])
374 return 0;
376 memcpy (proc->argv[x], arg, i);
377 proc->argv[x][i] = '\0';
378 } else {
379 proc->argv[x] = (char *) kmalloc (sizeof (char) * (i+1-y));
381 if (!proc->argv[x])
382 return 0;
384 memcpy (proc->argv[x], arg+y+1, i-y-1);
385 proc->argv[x][i-y-1] = '\0';
388 y = i;
389 x ++;
392 i ++;
395 return 1;
398 bool proc_arg_free (proc_t *proc)
400 if (!proc)
401 return 0;
403 if (!proc->argv || !proc->argc)
404 return 0;
406 unsigned i = 0;
408 while (i < proc->argc) {
409 kfree (proc->argv[i]);
410 i ++;
413 kfree (proc->argv);
415 proc->argc = 0;
417 return 1;
420 bool proc_arg_get (proc_t *proc, unsigned *argc, char **argv)
422 if (!proc)
423 return 0;
425 if (!proc->argv || !proc->argc || !argc)
426 return 0;
428 argv = proc->argv;
429 *argc = proc->argc;
431 return 1;
434 bool proc_flag_set (proc_t *proc, unsigned short flag)
436 if (!proc)
437 return 0;
439 if (proc->flags & flag)
440 return 0;
442 proc->flags |= flag;
444 return 1;
447 unsigned proc_page_fault ()
449 proc_t *proc = proc_find (_curr_task);
451 if (!proc)
452 return 0;
454 video_color (15, 0);
455 printf ("%s: signal SIGSEGV\n", proc->name);
457 /* send SIGSEGV signal to running process */
458 proc_signal (proc, SIGSEGV);
460 return 1;
463 unsigned proc_vmem_map (proc_t *proc)
465 #ifdef ARCH_i386
466 /* create new page_cover "shield" for process */
467 proc->task->page_cover = (page_ent_t *) page_cover_create ();
469 /* map kernel space */
470 page_mmap (proc->task->page_cover, (void *) 0x0, (void *) 0x400000, 1, 0);
472 /* map VESA double buffer memory - enough for 16bit 800x600 - 1MB for framebuffer */
473 page_mmap (proc->task->page_cover, (void *) 0x400000, (void *) proc->start, 1, 0);
475 /* calculate size of process image (binary file) */
476 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
478 /* map process image - app should think, that it is placed at 8MB in ram */
479 page_mmap (proc->task->page_cover, (void *) 0x800000, (void *) 0x800000+p, 0, 1);
481 /* map end of kernel space */
482 page_mmap (proc->task->page_cover, (void *) proc->start+p, (void *) 0x800000, 1, 0);
484 proc->heap = 0x800000;
485 #endif
486 return 1;
489 unsigned proc_vmem_unmap (proc_t *proc)
491 if (!proc)
492 return 0;
494 if (!proc->task)
495 return 0;
496 #ifdef ARCH_i386
497 if (!proc->task->page_cover)
498 return 0;
500 page_ent_t *page_cover = proc->task->page_cover;
502 /* switch to kernel page directory */
503 page_dir_switch (task_list.next->page_cover->page_dir);
505 /* unmap kernel area */
506 page_unmmap (page_cover, (void *) 0x0, (void *) 0x400000);
508 /* unmap framebuffer area */
509 //page_unmmap (page_cover, (void *) 0x400000, (void *) 0x500000);
511 /* unmap process image */
512 page_unmmap (page_cover, (void *) 0x400000, (void *) proc->start);
514 unsigned p = (unsigned) palign ((void *) (proc->end - proc->start));
516 /* unmap end of user-space */
517 page_unmmap (page_cover, (void *) 0x800000, (void *) 0x800000+p);
519 /* unmap the rest */
520 page_unmmap (page_cover, (void *) proc->start+p, (void *) 0x800000);
522 /* unmap the allocated memory */
523 page_unmmap (page_cover, (void *) 0x800000+p, (void *) proc->heap+p);
525 if (!page_cover_delete (page_cover)) {
526 DPRINT ("ERROR -> proc_vmem_unmap () - proc: %s", proc->name);
527 return 0;
530 proc->task->page_cover = 0;
531 #endif
532 return 1;
535 void *(*thread_entry) (void *);
536 void *thread_arg;
538 void proc_thread_context ()
540 thread_entry (thread_arg);
541 #ifdef ARCH_i386
542 sys_threadclose (0);
543 #endif
546 unsigned proc_thread_create (void *entry, void *arg)
548 proc_t *proc = proc_find (_curr_task);
550 if (!proc)
551 return 0;
553 char *name = "proc_thread";
555 unsigned p = (unsigned) entry;
557 thread_entry = (void *) p;
558 thread_arg = arg;
560 /* create new process thread */
561 task_t *task = (task_t *) task_create (name, (unsigned) &proc_thread_context, PROC_USER_PRIORITY);
563 if (!task)
564 return 0;
566 /* HACK: set task id same as current task (our process) */
567 if (proc->task) {
568 task->id = proc->task->id;
569 #ifdef ARCH_i386
570 /* use same page_cover too for correctly paging */
571 if (proc->task->page_cover)
572 task->page_cover = proc->task->page_cover;
573 #endif
576 /* NOTE: this is pretty needed, because thread argument and entry point is then same as previous */
577 schedule ();
579 DPRINT ("process: new thread '%s' : 0x%x", name, p);
581 return 1;
584 unsigned proc_thread_destroy (proc_t *proc, task_t *task)
586 /* we won't close main process thread */
587 if (proc->task == task)
588 return 0;
590 if (!task_done (task))
591 return 0;
593 DPRINT ("process: close thread '%s'", task->name);
595 return 1;
598 unsigned int init_proc (void)
600 proc_list.next = &proc_list;
601 proc_list.prev = &proc_list;
603 proc_kernel.task = task_find (0);
604 proc_kernel.heap = 0x800000;
605 proc_kernel.start = 0;
606 proc_kernel.end = 0;
608 return 1;