Delegate functions in PSPSDK (for cross-thread operations)

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Delegate functions in PSPSDK (for cross-thread operations)

Post by Torch »

How do I call a 'delegate' function in the PSPSDK?
Basically I am using a class in my main thread, and I launch one of its functions as a new thread. Now from the new thread how do I call a member function but have it run in the context of the main-thread.

Right now I'm using a crude method of setting up some global variables, and continuously checking the variables from the main thread, if a variable is set (by the new thread) the corresponding function is called in the main thread.
User avatar
jean
Posts: 489
Joined: Sat Jan 05, 2008 2:44 am

Post by jean »

The word delegate has been introduced by microsoft with their C# to mean a function pointer in a managed environment. If i understand, what you are basically asking is how to replicate the obj.Invoke(fnDelegate); to make a thread call a function in its context from another thread. This is not very simple and definitely not straightforward - if there's not a dedcated function that i don't know. A possible way is to pass the function pointer writing in a shared memory location and then unlock a semaphore. At least that's the way used in other c/c++ cross-platform projects.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

The semaphore method is basically the same as my global variable stuff. I don't need to go as far as a function pointer because I only need 2 or 3 specific functions which the main thread can decide depending on the value of the variable. However this will cause a delay depending on how often the main thread loops and checks the semaphore (if its a blocking wait then its more or less instant) but I want my main thread to do other processing as well instead of just blocking until the semaphore is unlocked. Since my main thread has a delay of 100000 it will take a short while before the function call occurs.

My specific problem is that I need to call some ordinary sce* functions from inside a syscon_debug_handler. However this is obviously not to be done as it blocks all syscon packets till the function returns and will cause very strange side effects, including hardware malfunction. Hence I'm setting a global from inside the syscon handler and that is being checked by the main thread whether to execute a function. The only problem here is the slight delay caused by the main loop's delaythread function as I don't want it hogging CPU.
moonlight
Posts: 567
Joined: Wed Oct 26, 2005 7:46 pm

Post by moonlight »

Not totally sure, but maybe threadman callbacks can resolve your problem.
You create the callback in a thread A, and then it can be notified from other thread B with sceKernelNotifyCallback, the function will be executed on context of thread A. However, thread A should be checking for callbacks using sceKernelCheckCallback or having entered in a a sleep/delay/wait state with one of the CB versions of those wait functions.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

Just tried it. In the main thread I used sceKernelDelayThreadCB for delaying.
The function is executing instantly (because the main thread is in DelayCB for most of the time anyway, the remaining code is small).

But when I call sceKernelNotifyCallback from inside a syscon debug handler, it again causes hardware malfunction. (Almost all sce* functions cause problems). Some times it shows no battery icon and shuts down, or it shows external power source, or screen starts flickering etc. (When such problem occurs it doesnt even go away with kernel reboot, or soft reset. Only cold boot will fix it.)

Only "normal" code without any external calls seems to work inside syscon debug handler.
TyRaNiD
Posts: 907
Joined: Sun Jan 18, 2004 12:23 am

Post by TyRaNiD »

I would ask what on earth you are doing, but then I realised you have no idea what you are doing so I can't be bothered to give you a sensible answer :)
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

TyRaNiD wrote:I would ask what on earth you are doing, but then I realised you have no idea what you are doing so I can't be bothered to give you a sensible answer :)
Its for Hold+. I'm using the syscon_debug_handler to read the keys while the Hold switch is enabled.

The problem is when I need to react to those keys, I can't call any useful functions from inside that function without screwing up the PSP, thats why I have to execute them from another thread.
Torch wrote:The function is executing instantly (because the main thread is in DelayCB for most of the time anyway, the remaining code is small).
If this sounded confusing, what I meant was, once the main thread is waiting in the sceKernelDelayThreadCB, when I notify callback from the syscon_ctrl function, the callback is executed instantly without any delay.
Last edited by Torch on Tue Feb 03, 2009 2:11 am, edited 3 times in total.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

Inside this function...

Code: Select all


sceSysconSetDebugHandlers(&syscon_debug_callbacks); // register on app start

......

static sceSysconDebugHandlers syscon_debug_callbacks =
{
	syscon_debug_callback0,
	syscon_transmit_callback,
	syscon_receive_callback,
	syscon_debug_callback3
};

void syscon_ctrl(sceSysconPacket *packet) // most sce* functions don't work properly inside this for obvious reasons.
{
	newButtons=0;
	rxd = packet->rx_data;

	raw_ctrl.Lx = 0;
	raw_ctrl.Ly = 0;

	switch(packet->rx_response)
	{
	case 0x08:
		raw_ctrl.Lx = rxd[4];
		raw_ctrl.Ly = rxd[5];
		goto SkipSetAnalog;
	case 0x07:
.....
}
As you can see, the syscon_ctrl function isn't exactly running in a second thread by started by me, I just said it was in the first post to prevent confusion due to ppl not knowing what syscon debug handler was, but its pretty much the same analogy because syscon_ctrl must be executing in some other thread started by the OS.
ctszy
Posts: 18
Joined: Sat Apr 12, 2008 11:18 pm

Post by ctszy »

not sure though.. but seems Booster has done sth similar with yours?
just Google "vshex_syscon" and take a look :)
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

ctszy wrote:not sure though.. but seems Booster has done sth similar with yours?
just Google "vshex_syscon" and take a look :)
This IS based on booster's syscon debug sample. I've just cut down on the unnecessary things.
TyRaNiD
Posts: 907
Joined: Sun Jan 18, 2004 12:23 am

Post by TyRaNiD »

Unfortunately really the best you can have is sceKernelNotifyCallback as it is able to be called in an interrupt context (which I assume this is). If that is still screwing things up, well it is difficult :) You could try EventFlags but not sure that is going to significantly help you.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

TyRaNiD wrote:Unfortunately really the best you can have is sceKernelNotifyCallback as it is able to be called in an interrupt context (which I assume this is). If that is still screwing things up, well it is difficult :) You could try EventFlags but not sure that is going to significantly help you.
Well sceKernelNotifyCallback is causing malfunctions like I mentioned before. I didn't know about EventFlags functions, I'll try it now and hope it also doesn't screw up.

BTW I was wondering how much of a performance overhead this is consuming by calling this debug handler interrupt (atleast 60 times a second for the controller packets alone, it must call and return immediately much more often for other packet types)? I don't notice any slowdown in games though.
ne0h
Posts: 386
Joined: Thu Feb 21, 2008 2:15 am

Post by ne0h »

I'm not totally sure but EventFlags is like global variabiles, there's no way to send a "immediate request" to another thread, there's sceKernelPollEventFlag or sceKernelWaitEventFlag, but is the same thing as:

Code: Select all

if(global_var == value)
[...]

OR

while(global_var != value); // Probably with some delay
I don't know very well what are you doing, but can't you use another thread with less delay time? Or can be a problem during gameplay?
I've never made a plugin so ...
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

Event flags has a wait timeout, so I guess its effectively the same as DelayThreadCB. If the event occurs while its waiting it will fire, other wise it goes to the next iteration and executes my other code first before waiting again.

I haven't tried it in my plugin yet to see if it screws up.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

@TyRaNiD

I noticed you didn't read my PM. I assumed you read it first yesterday and then replied here about the EventFlags. It contains the source code of my plugin, so if you take a look at that it might help with some ideas.
User avatar
Jim
Posts: 476
Joined: Sat Jul 02, 2005 10:06 pm
Location: Sydney
Contact:

Post by Jim »

Is it not possible to have a high priority thread waiting on a semaphore. In your debug thread you raise the semaphore and yield. That should make the high priority thread run immediately.

Jim
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

I can't call the sema functions from the debug thread, it also malfunctions.

I'm yet to try the EventFlags, I'm away from my dev pc at the moment.
User avatar
Torch
Posts: 825
Joined: Wed May 28, 2008 2:50 am

Post by Torch »

I wasn't able to get event flags working properly.

Is there anything special I have to do while using sceKernelNotifyCallback from an interrupt context? Sometimes it works, but during some games (specifically God of War) it causes an instant crash (full power off, no led, no display, and an audible pop from the speakers).
Post Reply