forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Multi-thread in PSP failed . Need help

 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
jesil



Joined: 17 Feb 2009
Posts: 10

PostPosted: Mon Jun 01, 2009 10:40 pm    Post subject: Multi-thread in PSP failed . Need help Reply with quote

Hi ,I am writing an game engine on psp. I need to play music in my game . So i study the mp3 sample in the PSPSDK wrote by raphael.
Then i want to create a thread to deal with playing music while i can do something else in the game. But when i start the thread , it freeze . I don't know why. Please if you counld help me.Here is my part of code .

Code:



PSP_MODULE_INFO("LevolAVG", 0, 1, 6);
PSP_MAIN_THREAD_ATTR(0);
PSP_HEAP_SIZE_KB(18*1024);
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
   sceKernelExitGame();

   return 0;
}
int CallbackThread(SceSize args, void *argp)
{
   int cbid;
   cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
   sceKernelRegisterExitCallback(cbid);

   sceKernelSleepThreadCB();

   return 0;
}

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
   int thid = 0;

   thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0x3F40, 0, 0);
   if(thid >= 0)
   {
      sceKernelStartThread(thid, 0, 0);
   }

   return thid;
}

//Functions Definition and Variables Delaration

void show_menu(void);

void show_menu(void)
{
    
   printf("Press circle to load a imge\n");
   
   
}

int main()
{     
   int errorInteger=0;

   
   pspDebugScreenInit();
   SetupCallbacks();
   sceDisplaySetMode(0, SCREEN_WIDTH, SCREEN_HEIGHT);
   EnableGU();

   errorInteger=FreeTypeInitial();
   if ( errorInteger == 0 )
   {
      ERRORMSG("Error Error in FreeTypeInitial\n");
   }
   
   errorInteger =   MovieInitial();
   if (errorInteger == 0)
   {
      ERRORMSG("Error in Movie Initial\n");
   }

   ScriptFlow("my.txt");
   sceKernelSleepThread();
   return 0;
}



The code above is my main thread. while in the ScriptFlow functions ,i start the thread as follows.

Code:

   myAvgThread->MusicPlayThread=sceKernelCreateThread("playmusic",PlayMusicThread,0x8,0x10000,0,0);
   
   if(myAvgThread->MusicPlayThread < 0)
   {
      ERRORMSG("ERROR: creat startPlay thread failed returned 0x%08X\n", myAvgThread->MusicPlayThread);
   }

      sceKernelStartThread(myAvgThread->MusicPlayThread,4,&myAvgThread);
   
   sceKerneSleepThread();



It can play music but my program freeze.I can not do anything else while listening to the music i Played. But indeed i want do some display actions while playing music.


So counld somebody tell me my fault in this program.
Back to top
View user's profile Send private message
Torch



Joined: 28 May 2008
Posts: 842

PostPosted: Mon Jun 01, 2009 11:36 pm    Post subject: Reply with quote

Priority of 0x8 is very high. Try reducing it less than the main thread. Is your music thread delaying to allow other threads to execute?
Back to top
View user's profile Send private message
jesil



Joined: 17 Feb 2009
Posts: 10

PostPosted: Tue Jun 02, 2009 12:20 am    Post subject: Reply with quote

THX for Torch reply.
So it means in the PSP,it cannot run two threads at the same time .should i add scekerneldelaythread or other functions to delay music thread and let main thread run.
i ajust my code . and the new code are as follows :
Code:


int PlayMusicThread(SceSize input_lenth, void *input)
{

       volatile AvgThread *myAvgThread = *((void**) input);

       SceCtrlData pad;
       SceUID  fd;

       int status;

       sceCtrlSetSamplingCycle(0);
       sceCtrlSetSamplingMode(0);
 
   
   LoadMp3Module();

   
   // Open the input file
   fd = sceIoOpen( myAvgThread->filename, PSP_O_RDONLY, 0777 );


   status = sceMp3InitResource();
   if (status<0)
   {
      ERRORMSG("ERROR: sceMp3InitResource returned 0x%08X\n", status);
   }
   
   // Reserve a mp3 handle for our playback
   SceMp3InitArg mp3Init;
   mp3Init.mp3StreamStart = 0;
   mp3Init.mp3StreamEnd = sceIoLseek32( fd, 0, SEEK_END );
   mp3Init.unk1 = 0;
   mp3Init.unk2 = 0;
   mp3Init.mp3Buf = mp3Buf;
   mp3Init.mp3BufSize = sizeof(mp3Buf);
   mp3Init.pcmBuf = pcmBuf;
   mp3Init.pcmBufSize = sizeof(pcmBuf);
   
   SceInt32 handle = sceMp3ReserveMp3Handle( &mp3Init );
   
   
   // Fill the stream buffer with some data so that sceMp3Init has something to work with
   FillMp3StreamBuffer( fd, handle );
   
   status = sceMp3Init( handle );

   
   int channel = -1;
   int samplingRate = sceMp3GetSamplingRate( handle );
   int numChannels = sceMp3GetMp3ChannelNum( handle );
   int lastDecoded = 0;
   int volume = PSP_AUDIO_VOLUME_MAX;
   int numPlayed = 0;
   int paused = 0;
   
   while (1)
   {
      if (!paused)
      {
         sceKernelDelayThread(100000);
         // Check if we need to fill our stream buffer
         if (sceMp3CheckStreamDataNeeded( handle )>0)
         {
            FillMp3StreamBuffer( fd, handle );
         }

         short* buf;
         int bytesDecoded;
         int retries = 0;
         // We retry in case it's just that we reached the end of the stream and need to loop      
         
         for (retries = 0;retries<1;retries++)
         {
            bytesDecoded = sceMp3Decode( handle, &buf );
            if (bytesDecoded>0)
               break;
            
            if (sceMp3CheckStreamDataNeeded( handle )<=0)
               break;
            
            if (!FillMp3StreamBuffer( fd, handle ))
            {
               numPlayed = 0;
            }
         }
      
         
         // Nothing more to decode? Must have reached end of input buffer
         if (bytesDecoded==0 || bytesDecoded==0x80671402)
         {
            paused = 1;
            sceMp3ResetPlayPosition( handle );
            //numPlayed = 0;
         }
         else
         {
            // Reserve the Audio channel for our output if not yet done
            if (channel<0 || lastDecoded!=bytesDecoded)
            {
               if (channel>=0)
                  sceAudioSRCChRelease();
               
               channel = sceAudioSRCChReserve( bytesDecoded/(2*numChannels), samplingRate, numChannels );
            }
            // Output the decoded samples and accumulate the number of played samples to get the playtime
            sceAudioSRCOutputBlocking( volume, buf );
         }
      }
      
      
    }
 
      if (channel>=0)
      sceAudioSRCChRelease();
   
   status = sceMp3ReleaseMp3Handle( handle );

   
   status = sceMp3TermResource();

   
   status = sceIoClose( fd );

    return 0;
}

I delete some debug information. I call scekerneldelaythread () in the music playing thread . and i change the music thread prioty to 45.
Now the program turns out to blink several times (which i think the delay of the music playing causes) and then freeze.
And could anybody help me for that problem.And is there any examples to explain how two threads run in the PSP.Thank you very much.
Back to top
View user's profile Send private message
jesil



Joined: 17 Feb 2009
Posts: 10

PostPosted: Tue Jun 02, 2009 3:47 pm    Post subject: Reply with quote

Ok it's me .Finally I figure it out .
We should call sceKernelDelayThread() to delay the current thread and let the thread which you want to start run. And in my Music playing thread . I should add delay time to a certain amount , and thus the thread can run perfectly. Maybe different threads demand different delay time ,depending on initialization of the functions .

So it is my experience .Wish it helps somebody .
Back to top
View user's profile Send private message
jesil



Joined: 17 Feb 2009
Posts: 10

PostPosted: Tue Jun 02, 2009 3:56 pm    Post subject: Reply with quote

And in this mp3 playing thread ,it needs about 100000us delay
Back to top
View user's profile Send private message
Torch



Joined: 28 May 2008
Posts: 842

PostPosted: Tue Jun 02, 2009 4:08 pm    Post subject: Reply with quote

jesil wrote:
And in this mp3 playing thread ,it needs about 100000us delay


That depends on how much audio is buffered.
Back to top
View user's profile Send private message
Devun_06



Joined: 17 Jun 2006
Posts: 15

PostPosted: Sun Jan 24, 2010 4:43 am    Post subject: Reply with quote

It is quite old, but this thread was my better option to gathering whether or not I may have had a thread issue, instead of opening an entire new one, since this may actually already have a solution to my problem.


Code:

PSP_MODULE_INFO("LevolAVG", 0, 1, 6);
PSP_MAIN_THREAD_ATTR(0);
PSP_HEAP_SIZE_KB(18*1024);
/* Exit callback */
int exit_callback(int arg1, int arg2, void *common)
{
   sceKernelExitGame();

   return 0;
}
int CallbackThread(SceSize args, void *argp)
{
   int cbid;
   cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
   sceKernelRegisterExitCallback(cbid);

   sceKernelSleepThreadCB();

   return 0;
}

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void)
{
   int thid = 0;

   thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0x3F40, 0, 0);
   if(thid >= 0)
   {
      sceKernelStartThread(thid, 0, 0);
   }

   return thid;
}

//Functions Definition and Variables Delaration

void show_menu(void);

void show_menu(void)
{
   
   printf("Press circle to load a imge\n");
   
   
}

int main()
{     
   int errorInteger=0;

   
   pspDebugScreenInit();
   SetupCallbacks();
   sceDisplaySetMode(0, SCREEN_WIDTH, SCREEN_HEIGHT);
   EnableGU();

   errorInteger=FreeTypeInitial();
   if ( errorInteger == 0 )
   {
      ERRORMSG("Error Error in FreeTypeInitial\n");
   }
   
   errorInteger =   MovieInitial();
   if (errorInteger == 0)
   {
      ERRORMSG("Error in Movie Initial\n");
   }

   ScriptFlow("my.txt");
   sceKernelSleepThread();
   return 0;
}


I added a phony identifier to jesil's ScriptFlow function below. Only for easing the comprehension strain.
Code:

void * ScriptFlow(char *)
{
myAvgThread->MusicPlayThread=sceKernelCreateThread("playmusic",PlayMusicThread,0x8,0x10000,0,0);
   
   if(myAvgThread->MusicPlayThread < 0)
   {
      ERRORMSG("ERROR: creat startPlay thread failed returned 0x%08X\n", myAvgThread->MusicPlayThread);
   }

      sceKernelStartThread(myAvgThread->MusicPlayThread,4,&myAvgThread);
   
   sceKerneSleepThread();
}



jesil wrote:
Ok it's me .Finally I figure it out .
We should call sceKernelDelayThread() to delay the current thread and let the thread which you want to start run. And in my Music playing thread . I should add delay time to a certain amount , and thus the thread can run perfectly. Maybe different threads demand different delay time ,depending on initialization of the functions .

So it is my experience .Wish it helps somebody .


1.) Okay, so you effectively start the script flow, and then, immediately after it, you put the main thread into sleep mode.
2.) Next, you start another thread, the music thread, and launch it at a decently high priority to avoid anything near real-time. Then, you sleep the main thread again.
3.) As you continue, you then place a delay at a 10th less than a second, at every instance the separate music thread is NOT paused in the dead lock.

I also noticed your ScriptFlow() captures the error, and handles it. But, from how it seems, it quickly forgets the thread wasn't able to be started, and follows up on attempting to call a thread that wasn't created successfully.

So, are you saying that this is the proper threading technique?
Code:

int  function thread();
void make thread();

void make thread()
{
create thread( function thread);
launch thread( function thread);
sleep main thread();
}

int  function thread()
{
          don't sleep function thread();

          while(1)
          {
               delaythread(10000);
          }
 }

int main()
{

make thread();
sleep main thread again();

while(1)
{

delaythread(100000);
}
end program();
}

I noticed you said delay to let the new thread run, so does that mean the main threads delay should come immediately after the launch thread(); where the main thread's sleep call is?
Now, I'm confused, why sleep the thread twice? By trial and error, you can adjust the delay to threads, but when you said you have to delay the primary thread, why is that if it's already placed in a subtle state such as sleep, or anything similar? If sleep isn't sufficient for that, what is the use of it? When would you wake the sleep thread? I think this is valuable information that may actually help me quite a bit, since your error seems a lot like my own at the moment.http://forums.ps2dev.org/viewtopic.php?p=87015#87015
Back to top
View user's profile Send private message
Jim



Joined: 02 Jul 2005
Posts: 487
Location: Sydney

PostPosted: Sun Jan 24, 2010 8:40 am    Post subject: Reply with quote

Look up Cooperative Multitasking.
When a thread is running, nothing else[1] can run
When a thread sleeps, it's put on a queue for its priority level with a restart time of now+sleep time, and the next queued highest priority thread that is ready to run is restarted.
Every thread must play this game of running for a short time then sleeping for it to work.

So there is no 'sleep a thread twice in a row'. It just means it skips being scheduled and the next thread runs.

Jim
[1] there are exceptions, like interrupt handlers.
_________________
http://www.dbfinteractive.com
Back to top
View user's profile Send private message Visit poster's website
Devun_06



Joined: 17 Jun 2006
Posts: 15

PostPosted: Sun Jan 24, 2010 1:12 pm    Post subject: Reply with quote

Jim wrote:
Look up Cooperative Multitasking.
When a thread is running, nothing else[1] can run
When a thread sleeps, it's put on a queue for its priority level with a restart time of now+sleep time, and the next queued highest priority thread that is ready to run is restarted.
Every thread must play this game of running for a short time then sleeping for it to work.

So there is no 'sleep a thread twice in a row'. It just means it skips being scheduled and the next thread runs.

Jim
[1] there are exceptions, like interrupt handlers.


Thanks Jim, I took your advice, I reviewed plenty of documents, but of them all, the most useful I could find were these:
Code:

http://www.netrino.com/Embedded-Systems/How-To/RTOS-Preemption-Multitasking
http://en.wikipedia.org/wiki/Computer_multitasking
http://www.softvelocity.com/Clarion/pdf/Cooperative%20threading%20versus%20Preemptive%20threading.pdf
http://en.wikipedia.org/wiki/Thread_%28computer_science%29
http://c2.com/cgi/wiki$?CooperativeThreading


And the best, was :
http://wiki.tcl.tk/20153 It sucked on explaining the code itself, and doesn't look like C or or any language I've come across. But, at the least, it kindof gave a simple frame work to the design.

Code:
load ./tcor.so

 set cmd {
  while 1 {
   puts HELLO
   tcor-yield
  }
 }

 tcor-spawn $::cmd

 while 1 {
  puts MAIN
  tcor-yield
  after 1000
 }


Still though, none of them fully explained sleep, suspend, or any of the other terminology used int the pspthreadman.h library. Which, essentially, is getting me no where, all of the material I found basically reworded "FlatMush" at http://www.psp-programming.com/forums/index.php/topic,3820.0.html, but in poorer methods using way more words. Except http://www.netrino.com/Embedded-Systems/How-To/RTOS-Preemption-Multitasking gave a very good visual illustration, to explain another threading method including Interrupts.

It's proving quite hard to find, could someone point me to the best material they've found for this topic. I'd definitely love to read it, and follow up on my work.

Thanks a lot though Jim, I appreciate your assistance. I completely understand how the concept works, my only problem now though, is how do I implement it. Doing so, still is difficult to do since I haven't completely wrapped my brain around how you explained sleep. What do you mean by NOW TIME when you said NOW + SLEEP time, and by sleep time, do you mean the delay time? I don't recall sleep having a time-stamp, I'm assuming by your explanation that it only yields the CPU over to the next thread, right? Does sleep record, or set a time or anything?

EDIT:
I found a FANTASTIC source to follow, even better than a framework. I wouldn't have assumed the pspthreadman.h would be built to resemble Java like code. Thanks Jim, that was very helpful. I couldn't have found it without you telling me what the name of it was!

So, basically, the concept still flows completely, there is no actual sleep, just a delay(0), and now that the CPU has moved on, it won't go back till it's completed it's job with other threads next in line, threads with higher priority, or other threads yield with a delay or sleep themselves.

I'm going to assume that Sleep, and Delay(0) are the same.

Go Here: http://www.geom.uiuc.edu/~daeron/docs/javaguide/java/threads/states.html
Back to top
View user's profile Send private message
jesil



Joined: 17 Feb 2009
Posts: 10

PostPosted: Mon Jan 25, 2010 4:06 pm    Post subject: Reply with quote

Ok, i've read your problem,But i can just explain the few things you mentioned above.
Althougn psp support multithread working ,it doesn't mean that it can run two thread at the same time.When a thread is runing ,other threads can not make any function.The Other threads wait until the running thread delay. So you should always add "scekerneldelay(xxx)" in your thread to make other thread run. In my opinion,i call it suspend. SleepThread is not reqaired in my Project.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group