About wait()

Posted By: WretchedSid

About wait() - 11/02/12 06:24

So, one of the biggest mysteries for me about Gamestudio is wait(), I have talked with quite a few people about it and no one really has a good idea how it works internally. Although it's commonly agreed to be one huge dirty stack hack.

From what I can see, a call to wait() isn't just a simple function call because it returns the currently running function. Instead I think it's actually more like a macro that expands into something like:
Code:
if(notifyScheduler(&stackTop, n) == 0)
   return;



The scheduler will then take the current stack pointer and simply copies everything from stackTop down to the current stack pointer into a buffer. StackTop is the address of the first argument that was pushed on the stack, which is also the reason for a) the interesting layout of local variables on the stack (and their weak scope) as well as b) the not existence of variadic functions (if variadic functions would exist, the compiler had to compile multiple versions of the function for each possible number of arguments).

The return address might be passed as well to the scheduler, but I guess it's much easier to just grab it of the stack upon entry, it's also much more accurate and doesn't require work from the linker.

I'm not too sure if some of the registers need to be saved as well, I tried to think of a few good reasons but as far as I can see it's impossible to call wait() from somewhere when there is data in the registers that isn't saved already somewhere.

The scheduler then creates a new entry, saves my and you along with the buffer and return address and that's it.
Then the main runloop finishes it's current step, everything is rendered etc, and then the scheduler kicks in on the next iteration and works off it's list checking which functions are due. I guess what happens there is that it grabs the current stack pointer, modifies the return address on the saved stack, moves something else than zero into eax (to make my pseudo code above work) and then copies the saved stack on the current stack and also restores my and you. Then it makes a jmp to the stored return address and thats it.

At least that's how I imagine it works from all I can see, but what would really interest me: How close is that to the truth? How does wait() actually work?
Posted By: jcl

Re: About wait() - 11/02/12 08:28

It is pretty close. Only the issue with variadic functions has a different reason. Here's our source for wait(), somewhat simplified:

Code:
void CS_Wait(fixed time)
{
	static byte *local_stack,*local_offs;
	_asm
	{
		mov local_offs,ebx
		mov local_stack,ebp		
	}
	time -= 1;

// retrieve function name, stack size, and start address information
	byte *stack = local_stack+3*4; 
	byte *code = (byte*)((DWORD*)local_stack)[1]; // current return address from the stack
	char *name;		// of the function
	void *codestart;	// of the function
	long stacksize;		// local stack size
	long parasize;		// function parameter size
	CS_GetFunctionInfo(code,&name,&stacksize,&parasize,&codestart);
	CS_SchedulerInsert(code,stack,stacksize,code-local_offs,time,codestart,name);

// return to the caller
	_asm
	{
		mov esp,stack
		add esp,stacksize;	// skip local vars
		pop edi			// pop original registers
		pop esi  
		pop ebx  
		pop ebp
		ret			// back to caller
	}
}


Posted By: TechMuc

Re: About wait() - 11/02/12 09:14

wow, thanks a lot for this answer. But one annotation:

Please, please please make this CS_GetFunctionInfo public (export symbols to acknex.dll).
This function would really really help a lot (e.g. getting stacksize of a single function, or the parametersize).

I do not need entries in afuns.h (or similar), just an export, so i can retrieve the address via GetProcAddress.

This would probably allow to implement a "real" profiler.
Posted By: WretchedSid

Re: About wait() - 11/02/12 13:21

Wow, thanks a lot indeed! That clears up a lot of things I've been wondering about.
Although I'm now confused about variadic functions, it seemed like a pretty good explanation to me but now I'm baffled what the actual reason is. Can you shed some light into this as well?
Posted By: TechMuc

Re: About wait() - 11/03/12 12:59

btw: Is it correct that CS_GetFunctionInfo(code,&name,&stacksize,&parasize,&codestart);
expects 6 Parameters (before code, another parameter, which probably indicates the first lite-c function)?

If so could you please also export this variable? I think if you provide me with those 3 Functions:

1) internal wait
2) CS_GetFunctionInfo
3) 1st parameter of CS_GetFunctioninfo (My current way of calculating this parameter is:
Code:
void* _ev = (void*)a7_dll::engine_getscript("main");
global_code_start_address = (void*)(((int)_ev) & 0xFFFF0000);


which might be correct for my test script but for 100% nur for any 3dgs project laugh - [edit]I know now, that this is absolutly wrong[/edit]

a) Call Stack
b) debugging of local variables
c) debugging of argument values (okay more or less the same)
d) profiling

would be possible...
Posted By: TechMuc

Re: About wait() - 11/04/12 22:37

Edit: Some kind of remark, with another video advertising post. Please help me out here by exporting those internal functions. I'm currently working with "fix relative" internal positions to retrieve the function pointers, which is a) unsafe b) not good for engine upgrades.

Video that i do not fake this stuff: http://www.dev-software.com/led/video/performance_1/Performance_Video_1.html
Posted By: jcl

Re: About wait() - 11/05/12 13:03

The first parameter was the codebase. We'll export this function in a future update so that you can externally use it.
© 2024 lite-C Forums