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 

Exception handling capabilities

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



Joined: 05 Jan 2008
Posts: 489

PostPosted: Tue May 20, 2008 1:00 am    Post subject: Exception handling capabilities Reply with quote

I'm developing a small C++ library that heavily uses inheritance and polymorphinsm, and depends upon exceptions implementation. I'm not using std in any way (i'm not satisfied of it on certain technical and license aspects) but a quick look into some source code made me aim my attention on -fno-exceptions flag (that -if i understood well- makes code workaround the lack of hw exceptions handling background with a serie of if-like structures). Speaking of PSP-specific code, i noticed -fno-exceptions is ALWAYS set in all sources i inspected. Why? And: is PSP technically capable of handling exceptions "the classical way"??
Thanks for your attention
jean
Back to top
View user's profile Send private message
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Tue May 20, 2008 5:12 am    Post subject: Reply with quote

the lack of hw exceptions ?

no, -fno-exceptions option has nothing about hardware exceptions. This is merely two different definitions indeed. c++ exceptions are used through "try/catch".

if I'm not wrong, to have c++ exception handling (with RTTI for dynamic_cast as well), you need to provide specifically some files with run-time functions to handle c++ exceptions properly. I guess we use -fno-exceptions because those files are probably not adapted so they could work on PSP.

To be frank, I'm not sure having -fno-exception(s) would prevent you from using "try/catch" (using for instance a simple setjmp/longjmp version) because I never tried so
Back to top
View user's profile Send private message
jean



Joined: 05 Jan 2008
Posts: 489

PostPosted: Tue May 20, 2008 8:30 am    Post subject: Reply with quote

sorry, that "hw" before "exception" was not intended...it escaped from my fingers :) !! (i was to mean the "traditional" built-in way of handling exceptions) In fact the only thing i care is performance when making heavy use of software try..catch that surely has nothing to do with hw exception like a cpu issued "div by zero" (even if visual c++ seems to merge the two things in a weird manner...) Are you basically saying "if you don't try, you'll never know" ?
Back to top
View user's profile Send private message
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Tue May 20, 2008 8:41 am    Post subject: Reply with quote

jean wrote:
Are you basically saying "if you don't try, you'll never know" ?


kinda :)

I'm not sure a lot of us were paying any attention about -fno-exceptions -no-rtti and were using them because they were already set in template or sample Makefiles.

EDIT:

"try/catch" are accepted when compiled but there is no special generated code to handle c++ exception (as if they were comments). However, "throw" is refused : "error: exception handling disabled, use -fexceptions to enable"
Back to top
View user's profile Send private message
pspZorba



Joined: 22 Sep 2007
Posts: 156
Location: NY

PostPosted: Tue May 20, 2008 9:05 am    Post subject: Reply with quote

Quote:
I'm not sure a lot of us were paying any attention about -fno-exceptions -no-rtti and were using them because they were already set in template or sample Makefiles.


actually generally rtti slows the exe and makes it fatter. And the cases in which you really need them are rather rare.

and even if try/catch is more usefull, unfortunatly it makes the code unreadable (IMHO). That's probably why nobody never change those options.
_________________
--pspZorba--
NO to K1.5 !
Back to top
View user's profile Send private message
jean



Joined: 05 Jan 2008
Posts: 489

PostPosted: Wed May 21, 2008 6:52 pm    Post subject: Reply with quote

Quote:
That's probably why nobody never change those options.

Ok, I'll try to use -fexceptions ....
Back to top
View user's profile Send private message
Heimdall



Joined: 10 Nov 2005
Posts: 259
Location: Netherlands

PostPosted: Wed Feb 18, 2009 11:46 pm    Post subject: Reply with quote

Any success with exception handling? I'm trying to get it work but aparently it just hangs, here's the code:

Code:
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>

/* Define printf, just to make typing easier */
#define printf  pspDebugScreenPrintf

/* Define the module info section */
PSP_MODULE_INFO("cppException", 0, 1, 1);

/* Define the main thread's attribute value (optional) */
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);

#include <exception>
using namespace std;

class myexception: public exception
{
   virtual const char* what() const throw()
   {
      return "My exception happened";
   }
} myex;

int main (void)
{
   pspDebugScreenInit();
   SceCtrlData pad;
   
   try
   {
      throw myex;
   }
   catch (exception& e)
   {
      printf("%s\n", e.what());
   }
   
   printf("\nPress X to quit.\n");

   for (;;)
   {
      sceCtrlReadBufferPositive(&pad, 1);
      if (pad.Buttons & PSP_CTRL_CROSS)
         break;
   }
   sceKernelExitGame();

   return 0;
}


Am i doing something wrong?
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
jean



Joined: 05 Jan 2008
Posts: 489

PostPosted: Thu Feb 19, 2009 7:25 pm    Post subject: Reply with quote

Since then, i used exceptions extensively and without issues... Don't know, maybe your makefile... let me look into an old project of mine....
makefile:
Code:
TARGET = SERIAL_ROBOT
OBJS = main.o Command.o GetMotorCommand.o GetSensorCommand.o MotorPacket.o Packet.o PacketFactory.o RcvGetMotorPacket.o RcvGetSensorPacket.o SerialComm.o serialPacketReaderMachine.o SetMotorCommand.o SndGetMotorPacket.o SndGetSensorPacket.o SndSetMotorPacket.o sioDriver.o callbacks.o MotorController.o

BUILD_PRX=1
PSP_FW_VERSION=390
INCDIR =
CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fexceptions -fno-rtti  -D "__PSP"
ASFLAGS = $(CFLAGS)

LIBS = -lstdc++

LIBDIR =
LDFLAGS =

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = SERIAL_ROBOT

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak


i specified my own type of base exception, never inherited from std::exception

exceptions.hpp:
Code:
#ifndef __Exceptions_H__
#define __Exceptions_H__

/// \brief RException class.
class RException
{
};

/// \brief CommInitException class.
class CommInitException: public RException
{
};

/// \brief WrongMachineStateException class.
class WrongMachineStateException: public RException
{
};
// ...etc...

#endif // __Exceptions_H__


Anyhow, where does the code hang? You can easily track the exact point setting some printf(); around: if it does hang on throw, try to write mujltiple catch statements ending with the (...) one just to make that code not hang, then you can dig the reason why you con't catch that type.

Code:
try
{
   // throwing code
}
catch (specializedException1 e)
{
  // ...
}
catch (specializedException2 e)
{
  // ...
}
catch (baseException e)
{
  // ...
}
catch (...) // you can never know what can happen...
{
  // ...
}
Back to top
View user's profile Send private message
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Fri Feb 20, 2009 9:41 am    Post subject: Reply with quote

If i'm not wrong, you need to provide a c++ exception handling implementation for PSP in gcc source. Gcc can generate calls to some functions and you need to implement them as they may be dependent on OS. As far as i know psp-gcc has no such implementation.
Back to top
View user's profile Send private message
Heimdall



Joined: 10 Nov 2005
Posts: 259
Location: Netherlands

PostPosted: Fri Feb 20, 2009 4:53 pm    Post subject: Reply with quote

that was what i thought hlide, and started to add a simple threading implementation to gcc based on an old haiku-os implementation that only tels gcc that this device can handle mutexes, however when i throw an exception the mutex locks everything (i guess i got it all wrong from the gcc barely existing docs).

I've reverted my patch and exceptions work out of the box like jean says both with base user defined exception or using the sdt::exception one.

I've tested with gcc 4.3.3 and newlib 1.16 / gcc 4.3.3 and newlib 1.17
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Torch



Joined: 28 May 2008
Posts: 842

PostPosted: Fri Feb 20, 2009 5:16 pm    Post subject: Reply with quote

Can someone explain exactly how to set this up and get try-catch working for a normal makefile?
Back to top
View user's profile Send private message
Heimdall



Joined: 10 Nov 2005
Posts: 259
Location: Netherlands

PostPosted: Fri Feb 20, 2009 7:50 pm    Post subject: Reply with quote

This is my test cpp file:

Code:
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspctrl.h>

/* Define printf, just to make typing easier */
#define printf  pspDebugScreenPrintf

/* Define the module info section */
PSP_MODULE_INFO("cppException", 0, 1, 1);

/* Define the main thread's attribute value (optional) */
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | HREAD_ATTR_VFPU);

#include <exception>
using namespace std;

class myexception: public exception
{
   virtual const char* what() const throw()
   {
      return "My exception happened";
   }
} myex;

int main (void)
{
   pspDebugScreenInit();
   SceCtrlData pad;
   
   try
   {
      throw myex;
   }
   catch (exception& e)
   {
      printf("%s\n", e.what());
   }
   
   printf("\nPress X to quit.\n");
   for (;;)
   {
      sceCtrlReadBufferPositive(&pad, 1);
      if (pad.Buttons & PSP_CTRL_CROSS)
         break;
   }
   sceKernelExitGame();

   return 0;
}


and this is my makefile:

Code:
TARGET = CppException
OBJS = main.o
LIBS = -lstdc++

INCDIR =
CFLAGS = -G0 -Wall -O2
CXXFLAGS = $(CFLAGS) -fno-rtti -fexceptions
SFLAGS = $(CFLAGS)

LIBDIR =
LDFLAGS =

XTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = C++ Exception Sample

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak


the the usual, make, copy eboot and run :) on the makefile the only difference is that i define -fexceptions instead of -fno-exceptions on the CXXFLAGS variable, and obviously link againts -lstdc++ because this is a cpp sample.

PS: I'm adding this sample to the SDK in my builds.
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Sat Feb 21, 2009 5:41 am    Post subject: Reply with quote

Heimdall wrote:
that was what i thought hlide, and started to add a simple threading implementation to gcc based on an old haiku-os implementation that only tels gcc that this device can handle mutexes, however when i throw an exception the mutex locks everything (i guess i got it all wrong from the gcc barely existing docs).

I've reverted my patch and exceptions work out of the box like jean says both with base user defined exception or using the sdt::exception one.

I've tested with gcc 4.3.3 and newlib 1.16 / gcc 4.3.3 and newlib 1.17

so you can use -fexception but not rtti (dynamic_cast<> unusable). If a bus error occurs, do you catch a C++ exception ?
Back to top
View user's profile Send private message
Heimdall



Joined: 10 Nov 2005
Posts: 259
Location: Netherlands

PostPosted: Sat Feb 21, 2009 6:06 am    Post subject: Reply with quote

hlide wrote:
so you can use -fexception but not rtti (dynamic_cast<> unusable). If a bus error occurs, do you catch a C++ exception ?


It works for user defined exceptions that are programatically thrown, meaning all classes that extend std::exception (or not, like jean example ) can be throw and catched. For bus errors I haven't tested those thoroughly. For those I need to have at least mutexes working, but my gcc code failed:

Code:

static inline int
__gthread_mutex_lock (__gthread_mutex_t * mutex)
{
  int stat;
  int thid;
  int own;
  int rtn;

  if (mutex->semid < 0)
  {
    mutex->semid = sceKernelCreateSema ("libgccMutex", 0x0100, 1, 1, 0);
  }

  thid = sceKernelGetThreadId ();
  stat = sceKernelCpuSuspendIntr ();
  if (mutex->owner < 0)
  {
    mutex->owner = thid;
    own = 1;
  }
  else
    own = 0;
  sceKernelCpuResumeIntr (stat);

  if (own || mutex->owner != thid)
  {
    rtn = sceKernelWaitSema (mutex->semid, 1, 0);
  }
  else
  {
    mutex->count++;
    rtn = 0;
  }
   
  return rtn;
}

static inline int
__gthread_mutex_trylock (__gthread_mutex_t * mutex)
{
  int stat;
  int thid;
  int own;
  int rtn;

  if (mutex->semid < 0)
  {
    mutex->semid = sceKernelCreateSema ("libgccMutex", 0x0100, 1, 1, 0);
  }

  thid = sceKernelGetThreadId ();
  stat = sceKernelCpuSuspendIntr ();
  if (mutex->owner < 0)
  {
    mutex->owner = thid;
    own = 1;
  }
  else
    own = 0;
  sceKernelCpuResumeIntr (stat);

  if (own || mutex->owner != thid)
  {
    rtn = sceKernelPollSema (mutex->semid, 1);
  }
  else
  {
    mutex->count++;
    rtn = 0;
  }
   
  return rtn;
}

static inline int
__gthread_mutex_unlock (__gthread_mutex_t * mutex)
{
  int rtn;

  if (mutex->owner == sceKernelGetThreadId ())
  {
    if (mutex->count > 0 && --mutex->count == 0)
    {
      rtn = sceKernelSignalSema (mutex->semid, 1);
      mutex->owner = -1;
      sceKernelDeleteSema (mutex->semid);
      mutex->semid = -1;
    }
  }
  else if (mutex->owner >= 0)
  {
    rtn = sceKernelSignalSema (mutex->semid, 1);
    mutex->owner = -1;
    sceKernelDeleteSema (mutex->semid);
    mutex->semid = -1;
    mutex->count = 0;
  }
  else
    rtn = -1;

  return rtn;
}


I tryed to get it working like they did on the Haiku project before they had a pthread implementation... but this is wrong, because this will cause a hand on every throw clause.

Maybe I understood the semaphore api wrong or passing the wrong arguments either...[/code]
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Sat Feb 21, 2009 7:27 am    Post subject: Reply with quote

if you need a mutex, why not using those :
sceKernelCreateMutex
sceKernelDeleteMutex
sceKernelLockMutex
sceKernelLockMutexCB
sceKernelTryLockMutex
sceKernelUnlockMutex
Back to top
View user's profile Send private message
Heimdall



Joined: 10 Nov 2005
Posts: 259
Location: Netherlands

PostPosted: Sat Feb 21, 2009 7:45 pm    Post subject: Reply with quote

i guess you're right, i didn't look for the mutex api, and it contains what gcc needs :) I'll try that...
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
Heimdall



Joined: 10 Nov 2005
Posts: 259
Location: Netherlands

PostPosted: Mon Feb 23, 2009 6:34 pm    Post subject: Reply with quote

hlide wrote:
if you need a mutex, why not using those :
sceKernelCreateMutex
sceKernelDeleteMutex
sceKernelLockMutex
sceKernelLockMutexCB
sceKernelTryLockMutex
sceKernelUnlockMutex


humm... those functions are only available in the SDK or DA SDK meaning I don't know the method signature... more work to do...
Back to top
View user's profile Send private message Visit poster's website MSN Messenger
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Tue Feb 24, 2009 6:39 am    Post subject: Reply with quote

Heimdall wrote:
hlide wrote:
if you need a mutex, why not using those :
sceKernelCreateMutex
sceKernelDeleteMutex
sceKernelLockMutex
sceKernelLockMutexCB
sceKernelTryLockMutex
sceKernelUnlockMutex


humm... those functions are only available in the SDK or DA SDK meaning I don't know the method signature... more work to do...


ok,

Code:

SceUID sceKernelCreateMutex(
  const char *name,
  unsigned int attributes, /* using a FIFO (0) or PRIORITIZED (256) THREAD QUEUE */
  int initial_count, /* the initial count of mutex when created */
  void *optional_parameters /* just pass 0 */
); // returns Mutex UID if >0

int sceKernelDeleteMutex(
  SceUID id /* Mutex UID */
); // returns 0 if OK

int sceKernelLockMutex(
  SceUID id, /* Mutex UID */
  int lock_count, /* > 0 */
  unsigned int *timeout /* In : 0 if no timeout or a pointer to a placeholder containing the max time value in ms. Out: time remaining when mutex is acquired */
); // returns 0 if OK or 0x800201a8 if timeout

int sceKernelLockMutexCB(
  SceUID id, /* Mutex UID */
  int lock_count, /* > 0 */
  unsigned int *timeout /* In : 0 if no timeout or a pointer to a placeholder containing the max time value in ms. Out: time remaining when mutex is acquired */
); // returns 0 if OK or 0x800201a8 if timeout

int sceKernelTryLockMutex(
  SceUID id, /* Mutex UID */
  int lock_count /* > 0 */
); // returns 0x800201c4 if current thread failed to own mutex or 0 if success

int sceKernelUnlockMutex(
  SceUID id, /* Mutex UID */
  int unlock_count /* >= 0 */
); // returns 0 if OK
Back to top
View user's profile Send private message
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Mon Mar 09, 2009 8:42 am    Post subject: Reply with quote

Ok let's imagine we have a kernel prx wich installs a exception handler and that we can call a handler individually for each different cause :

void exc_install_handler(int cause, void (*handler)(int, exc_t *exc));

Basically, the general exception we installed through a kernel prx will be called when an exception is raised. This exception will call the right handler in an array where the cause is index. The previous function exported by the kernel prx allows us to define an handler per cause : bus error, FPU error, etc.

Now, we can define some C++ exceptions this way :

Code:

 class HardwareException
 {
 public:
     HardwareException(exc_t *exc)
     {
         m_exc = exc;
     }
 protected:
     exc_t m_exc;     
 };

 template <class ExceptionClass> class ExceptionTranslator
 {
 private:
     class SingletonTranslator
     {
     public:
         SingletonTranslator()
         {
             exc_install_handler(ExceptionClass::cause(), handler);
         }

         static void handler(int, exc_t *exc)
         {
             throw ExceptionClass(exc);
         }
     };

 public:
     ExceptionTranslator()
     {
         static SingletonTranslator s_obj_Translator;
     }
 };

 // An example for BUS_ERROR
class SegmentationFault : public HardwareException, public exception
 {
 public:
     SegmentationFault(exc_t *exc) : HardwareException(exc), exception() {}
     static int cause() { return BUS_ERROR; }
     ...
 };

 ExceptionTranslator<SegmentationFault> g_obj_SegmentationFaultTranslator;

 // An example for FPU_ERROR
 class FloatingPointException : public HardwareException, public exception
 {
 public:
     FloatingPointException(exc_t *exc) : HardwareException(exc), exception() {}
     static int cause() { return FPU_ERROR; }
     ...
 };

 ExceptionTranslator<FloatingPointException> g_obj_FloatingPointExceptionTranslator;
Back to top
View user's profile Send private message
coolkehon



Joined: 20 Oct 2008
Posts: 355

PostPosted: Tue Mar 10, 2009 10:32 am    Post subject: Reply with quote

sorry to intrude on this post but how can i use c++ in a kernel prx i have been having a problem with that for the longest it never compiles
Back to top
View user's profile Send private message MSN Messenger
hlide



Joined: 10 Sep 2006
Posts: 750

PostPosted: Tue Mar 10, 2009 9:14 pm    Post subject: Reply with quote

huh this is just an example to show how we could handle C++ exception to throw when an hardware exception occurs (access to null pointer, divide error, etc.) which are not catchable with the actual psp-gcc.

I think if we could tweak the source of exception.prx (not sure about the name) which is a homebrew kernel prx to allow a user application to catch every hardware exception and dump the details with a blue screen of death.

I think we can modify it so we can add an array of exception handlers and an exported function to install a user handler to call. Nothing is in C++.

The code I posted in C++ shows how in our c++ application we can try to make hardware exceptions turn into c++ exception. To do so, we could load this kernel prx and import such a function to install a user handler per hardware exception category to call the right "throw".

This is just an idea for those who are interested with.


Last edited by hlide on Tue Mar 10, 2009 10:45 pm; edited 1 time in total
Back to top
View user's profile Send private message
jean



Joined: 05 Jan 2008
Posts: 489

PostPosted: Tue Mar 10, 2009 9:31 pm    Post subject: Reply with quote

very very nice...thank you for sharing: will surely use something like this.
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