Multitasking problem

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Multitasking problem

Post by Octocontrabass »

WinExperements
Member
Member
Posts: 97
Joined: Thu Jul 14, 2022 9:45 am
Contact:

Re: Multitasking problem

Post by WinExperements »

Hello, again!
I have problem with implementing child waiting, after i run program twice, first run works but state of parent are always are "running", but second process after exit, throws to me the #PF, what is reason?
Here how i implement the process waiting:

Code: Select all

if (runningTask->pid == 0 || pid < 0) return;
	if (!process_getProcess(pid)) {
		 printf("process_wait: no such process %d, system halted\n",pid); 
		 return;
	}
	struct process *p = process_getProcess(pid);
	p->state = 2;
	// update pointer
	process_yield();
process_exit:

Code: Select all

void process_exit(int pid,int exitCode) {
	process_getProcess(pid)->state = 1;
}
process_getProcess:

Code: Select all

struct process *process_getProcess(int pid) {
	return process_findID(pid);
}
process_findID:

Code: Select all

struct process *process_findID(int id) {
	clist_head_t *c = clist_find(task_list,process_findIdDispatcher,id);
	if (c) {
		return (struct process *)c->data;
	}
	return NULL;
}
And finally, the schedule function:

Code: Select all

// send end of interrupt to interrupt controller
	io_writePort(PIC_SLAVE_COMMAND , 0x20);
	io_writePort(PIC_MASTER_COMMAND , 0x20);
	struct process *next_task = NULL;
	// update clocks
	clocks++;
	// don't save context on first switch
	if (!fswitch || runningTask->state == PROCESS_RUNNING) {
		runningTask->esp = stack;
	}
	if (!fswitch) {
		if (!runningTask) {
			next_task = process_findByStatus(PROCESS_RUNNING);
		} else {
			next_task = process_findNextByStatus(PROCESS_RUNNING,runningTask->lAddr);
		}
	}
	if (next_task == NULL) {
		// first switch
		next_task = process_findByStatus(PROCESS_RUNNING);
	}
	if (next_task == NULL) {
		printf("Next task null\n");
		return stack;
	}
	if (runningTask->state == PROCESS_KILLING) {
		if (runningTask->parent != 0) { // idle task hasn't waiting for any pid
			struct process *parent = process_findID(runningTask->parent);
			if (parent->state != PROCESS_WAIPID) {
				printf("Cannot unlock parent: Parent didn't waiting for any child PID: %d\n",runningTask->pid);
			} else {
				parent->state = PROCESS_RUNNING;
				fswitch = true;
				return  idle->esp;
			}
			curTasks--;
			arch_destroyStack(runningTask->esp);
			pmml_free(runningTask->esp);
			pmml_free((void *)runningTask->dir);
			if (runningTask->kernelESP != 0) {
				pmml_free((void *)runningTask->kernelESP);
			}
			if (runningTask->page_start != 0) {
				pmml_freePages((void *)runningTask->page_start,runningTask->pages);
			}
			clist_delete_entry(task_list,(clist_head_t *)runningTask->lAddr);
			pmml_free(runningTask);
		}
	}
	if (next_task->wait_time != 0) {
		next_task->wait_time--;
		fswitch = true;
		return stack;
	}
	tss_set_stack(0x10,next_task->kernelESP);
	vmm_switch((int *)next_task->dir);
	fswitch = false;
	runningTask = next_task;
	return runningTask->esp;
}
Screenshot of error in attachments.
EDIT: I fixed #PF, but now i have #GP with error code 1, i just replace process_yield code to waiting for next interrupt, also i fixed the "ready" state bug
UPDATE 2: I fixed the #GP, but now tasks always points to idle, maybe problem in context saving in process_schedule?
Attachments
QEMU 01.09.2022 14_20_27.png
QEMU 01.09.2022 14_20_27.png (10.39 KiB) Viewed 2338 times
WinExperements
Member
Member
Posts: 97
Joined: Thu Jul 14, 2022 9:45 am
Contact:

Re: Multitasking problem

Post by WinExperements »

Hello!
And first about previous post, after this post i edited my scheduler method and add context save/switch.
And i have some problem: when i receive keyboard interrupt, the handler correctly returns to the process wait key function, but if this function returns(it's must return key if it pressed) it's jumps to 0x0000010 why?
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: Multitasking problem

Post by Octacone »

WinExperements wrote:but if this function returns(it's must return key if it pressed) it's jumps to 0x0000010 why?
It jumps to 0x10 because that's the "last" thing that was stored on the stack. Inspect it to make sure it's not corrupted.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
WinExperements
Member
Member
Posts: 97
Joined: Thu Jul 14, 2022 9:45 am
Contact:

Re: Multitasking problem

Post by WinExperements »

Hello again! How i can add switching to user mode for user's tasks using Brendan's multitasking tutorial?
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Multitasking problem

Post by Octocontrabass »

When you initialize the task, fill the stack with values that will make the task return to ring 3 when you switch to it.
WinExperements
Member
Member
Posts: 97
Joined: Thu Jul 14, 2022 9:45 am
Contact:

Re: Multitasking problem

Post by WinExperements »

Octocontrabass wrote:When you initialize the task, fill the stack with values that will make the task return to ring 3 when you switch to it.
How i can fill correctly it, because i fill it with some parameters to my user startup function, that switches to user mode and jumps to the entry point, but after the restoring it from the saved state, it's switches to kernel mode. Do i need to change my switch function?
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Multitasking problem

Post by Octocontrabass »

Task switches only happen in ring 0. If the task itself is meant to run in ring 3, then the saved/restored state should be inside an IRQ or syscall handler that will eventually return to ring 3.

If that's not happening, something is wrong with how you're switching tasks.
WinExperements
Member
Member
Posts: 97
Joined: Thu Jul 14, 2022 9:45 am
Contact:

Re: Multitasking problem

Post by WinExperements »

Octocontrabass wrote:Task switches only happen in ring 0. If the task itself is meant to run in ring 3, then the saved/restored state should be inside an IRQ or syscall handler that will eventually return to ring 3.
As I understand it, the context switch should be called in an IRQ or system call that will return to ring 3? Or what?
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Multitasking problem

Post by Octocontrabass »

A ring 3 task can only get to ring 0 by a syscall or an IRQ, so a ring 3 task can only call the context switch in a syscall or IRQ handler.

When some other task calls the context switch, the ring 3 task will resume in ring 0 in the syscall or IRQ handler.
devc1
Member
Member
Posts: 439
Joined: Fri Feb 11, 2022 4:55 am
Location: behind the keyboard

Re: Multitasking problem

Post by devc1 »

To switch to a user mode task from an IRQ you simply must save and restore the page table and segment registers CS, DS, SS, ES, GS, FS. When you select your task you must build a stack frame then "iret" and congrats, you have made it to user mode.

This must happen when CPL=0 (kernel mode), probably inside an IRQ handler.
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Multitasking problem

Post by Gigasoft »

There is a type of design called a single stack kernel, sometimes used for microkernels. In this case, the task switching code operates on the interrupt return frame. This is not by definition "wrong", but comes with its own set of challenges. On the plus side, it saves memory. There is a version of the L4 Pistachio kernel that does this, as does the Playstation 1 BIOS. Most kernels uses a separate stack for each thread, and task switching only involves switching stacks and saving and loading a few registers.
WinExperements
Member
Member
Posts: 97
Joined: Thu Jul 14, 2022 9:45 am
Contact:

Re: Multitasking problem

Post by WinExperements »

Hello! I am have again problem, that my keyboard wait key function returns to 0x10. How i can correctly save the ESP for tasks?
Here the saving code:

Code: Select all

void arch_saveContext(struct process *forWho,registers_t *stack) {
    registers_t *f = (registers_t *)forWho->esp;
    f->eax = stack->eax;
    f->ecx = stack->ecx;
    f->edx = stack->edx;
    f->ebx = stack->ebx;
    f->ebp = stack->ebp;
    f->esi = stack->esi;
    f->edi = stack->edi;
    f->eip = stack->eip;
    f->eflags = stack->eflags;
    f->useresp = stack->useresp;
}
My context switching function used iret instruction and useresp field to switch to task, before it i only loads register values from the registers_t structure.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: Multitasking problem

Post by Octocontrabass »

I already gave you an example of how to perform a context switch in another thread. The code simultaneously saves the current task's ring 0 stack pointer to the provided location and sets ESP to the new task's ring 0 stack pointer.

When you have one ring 0 stack per thread, you don't need to save or restore anything except the ring 0 stack pointer.
Post Reply