Yes, here I am again with another question

Code: Select all
void Foo()
{
//Thread running 'simultaneously' with the main thread.
}
...
CreateProcess(&Foo);
Thanks,
Creature
Code: Select all
void Foo()
{
//Thread running 'simultaneously' with the main thread.
}
...
CreateProcess(&Foo);
Code: Select all
int CreateThread(*foo)
{
int ParentPid = GetPID();
int myPID = fork();
// use PIDs to determine which copy is parent and child -- however you implemented fork()
if (myPID != ParentPID)
{
int ret = foo (args);
exit (ret);
}
return (wait_for_child());
}
I tried lots of things besides printing, I tried letting them do something else that is notable and not related to eachother in any way or using volatile variables, but none seems to work, the child process is the only process being run. I guess it must be some bug in my fork code, then.bewing wrote:Sounds like you need to do a little work on making your string printing functions be threadsafe.
I'd be more likely to guess that it's a bug in your scheduler -- for some reason, it's choosing to give the child process all of the timeslices, and none to the parent.Creature wrote: I tried lots of things besides printing, I tried letting them do something else that is notable and not related to eachother in any way or using volatile variables, but none seems to work, the child process is the only process being run. I guess it must be some bug in my fork code, then.
Well, that's not good.EDIT: I've noticed that the timer (PIT) just randomly stops as soon as I fork a process.
Code: Select all
/*
* ScheduleProcesses
* Switches processes if necessary, this is called by the process scheduler.
*/
void ScheduleProcesses()
{
/* If this variable is 0, multitasking has not been initialized yet. */
if(!CurrentProcess)
return;
/* Read some registers. */
unsigned ESP;
unsigned EBP;
unsigned EIP;
ASMV("mov %%ESP, %0" : "=r" (ESP) :);
ASMV("mov %%EBP, %0" : "=r" (EBP) :);
/* Read the instruction pointer, to see if processes have just been switched. */
EIP = ReadEIP();
/* Have processes just been switched? */
if(EIP == 0xABCDE)
return;
/* If processes weren't switched, they will be switched now. Save the current state. */
CurrentProcess->ESP = ESP;
CurrentProcess->EBP = EBP;
CurrentProcess->EIP = EIP;
/* Select the next process. */
CurrentProcess = CurrentProcess->Next;
/* Prevent going past the end of the linked list. */
if(!CurrentProcess)
CurrentProcess = ProcessQueue;
ESP = CurrentProcess->ESP;
EBP = CurrentProcess->EBP;
EIP = CurrentProcess->EIP;
/* Change paging directories (so MemoryManager knows what to do). */
CurrentDir = CurrentProcess->PageDirectory;
/* Go to the new process! */
ASMV(" \n"
"cli \n" /* Disable interrupts. */
" \n"
"mov %0, %%ecx \n" /* Save EIP in ECX. */
"mov %1, %%esp \n" /* Load ESP (stack pointer). */
"mov %2, %%ebp \n" /* Load EBP (base pointer). */
"mov %3, %%CR3 \n" /* Change page directories. */
" \n"
"mov $0xABCDE, %%eax \n" /* Allow us to see if processes were just switched when re-entering this function (see above). */
" \n"
"sti \n" /* Re-enable interrupts. */
"jmp *%%ecx " /* Jump to the point where the process left off (EIP was stored in ECX above). */
: : "r" (EIP), "r" (ESP), "r" (EBP), "r" (CurrentDir->Address));
}
Code: Select all
/*
* ForkProcess
* Forks the currently active process (clones it in a different memory space).
*/
int ForkProcess()
{
/* No more interrupts. */
ASMV("cli");
Process *Parent = (Process *) CurrentProcess; /* Cast away volatileness. */
PageDir *Dir = ClonePageDir(CurrentDir);
/* Create a new process. */
Process *RetProcess = reinterpret_cast<Process *>(MM->Alloc(sizeof(Process)));
RetProcess->PID = NextPID++;
RetProcess->ESP = 0;
RetProcess->EBP = 0;
RetProcess->EIP = 0;
RetProcess->Next = 0;
RetProcess->PageDirectory = Dir;
/* Add the process to the linked list. */
Process *Node = (Process *) ProcessQueue; /* Cast away volatileness. */
/* Find the last node. */
while(Node->Next)
Node = Node->Next;
Node->Next = RetProcess;
/* Fill in the entry point. */
unsigned EIP = ReadEIP();
/* Is this the parent process? */
if(CurrentProcess == Parent)
{
/* Set up the child process. */
unsigned ESP;
unsigned EBP;
ASMV("mov %%ESP, %0" : "=r" (ESP) :);
ASMV("mov %%EBP, %0" : "=r" (EBP) :);
RetProcess->ESP = ESP;
RetProcess->EBP = EBP;
RetProcess->EIP = EIP;
/* Re-enable interrupts. */
ASMV("sti");
return RetProcess->PID;
}
/* If this point is reached, this is the child process. */
return 0;
}
Schedule process is called when a timer interrupt occurs and switches processes all the time. Since I'm using JamesM's tutorials, I'm going to quote what James says (he explains best):yemista wrote:Why do you read the up? If schedule process is called doesnt that mean the process has switched?
This is what happens at the ReadEIP() in 'ScheduleProcess'.JamesM's Tutorials wrote: Read the instruction pointer. We do some cunning logic here:
One of two things could have happened when this function exits -
(a) We called the function and it returned the EIP as requested.
(b) We have just switched tasks, and because the saved EIP is essentially the instruction after read_eip(), it will seem as if read_eip has just returned.
In the second case we need to return immediately. To detect it we put a dummy
value in EAX further down at the end of this function. As C returns values in EAX,
it will look like the return value is this dummy value! (0x12345).
No, its a time bomb waiting to go off (or it already did). Your code is making assumptions on how the compiler treats the stack, which can vary under different optimizations. (I'm probably cracking down some tutorial here in the same time...)Creature wrote:(code snipped)
Looks perfectly fine, doesn't it?
Please quote what assumptions that code makes, and what it violates. I'm interested to know.Combuster wrote:No, its a time bomb waiting to go off (or it already did). Your code is making assumptions on how the compiler treats the stack, which can vary under different optimizations. (I'm probably cracking down some tutorial here in the same time...)Creature wrote:(code snipped)
Looks perfectly fine, doesn't it?
Since I'm too pendantic about these things, I would grab a debugger to see what's truly happening (or being executed)
Code: Select all
unsigned EIP = ReadEIP();
// new task starts from here
if(CurrentProcess == Parent)
{
unsigned ESP;
unsigned EBP;
// allocate variables on the stack, adjust ESP and/or EBP to make room for them
// (depending on compiler and options this may or may not happen)
ASMV("mov %%ESP, %0" : "=r" (ESP) :);
ASMV("mov %%EBP, %0" : "=r" (EBP) :);
// get modified EBP/ESP
RetProcess->ESP = ESP;
RetProcess->EBP = EBP;
RetProcess->EIP = EIP;
// store process with EIP with a mismatched stack
ASMV("sti");
return RetProcess->PID;
}
// once new process returns, it pops off the wrong return address, and the world says BOOM