LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices

Rate this Entry

Example: sig-handler funcs for C and C++ (throw-catch) PART 1

Posted 05-13-2012 at 11:22 PM by rainbowsally

Today's Features
  • THROW-CATCH in C
  • Translating signals to C++ throw-catch parameters.

To compile the C++ example these vars are set in mc2.def and should be similar for other methods of building it.
Code:
COMPILE = g++ -m32 -c -o # COMPILE <output_file> ...
CFLAGS = -Wall -g3 --save-temps
# or CFLAGS = -Wall -O2 # optimized
INCLUDE = -I $(SRCDIR) -I$(PREFIX)/include 

LINK = g++ -m32 -o # LINK <output_file> ...
LDFLAGS = # $(GCCDIR)/libgcc_eh.a
LIB = -L/usr/lib -L/opt/gcc-dbg/lib
To compile the C example

Code:
COMPILE = gcc -m32 -c -o # COMPILE <output_file> ...
CFLAGS = -Wall -g3 -std=gnu99 # --save-temps
# or CFLAGS = -Wall -O2 -std=gnu99 # optimized
INCLUDE = -I $(SRCDIR)

LINK = gcc -m32 -o # LINK <output_file> ...
LDFLAGS = # $(GCCDIR)/libgcc_eh.a
LIB = -L/usr/lib # -L$(PREFIX)/lib -L/opt/gcc-dbg/lib/
So let's first take a peek at the two versions of main for the C and C++ tests. These two versions are mutually exclusive and the makefiles are not the same either. Use whatever tricks you like to symlink or move files as required for the different builds if you want to see them both.

Note: This C++ code is the result of several attempts to get at the low level throw and catch functions (tracing into a debug version of the entire gcc installation) which ended up being much more complicated than this and couldn't be used in C at all.

file: src/main.cpp
Code:
// generic C++ source template created by new.main

#include <stdio.h>  // printf(), FILE*, etc.
#include <malloc.h> // malloc(), free()
#include <string.h> // strcpy(), memcpy(), etc.
#include <stdlib.h> // exit()

#include "signal-handler.h"

void dbg(){}

// seg fault corrected
void test_handled()
{
  printf("Test 1 (handled segfault):\n");
  try
  {
    PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
    {
      char* s = 0;
      s += 9;
      int c = *s;
      c = c; // use it
    }
    HANDLE(true);       // handle signals and flag = continue normally
    POP_HANDLER();      // end HANDLER block to continue execution
    
    if(throw_code == 11)
    {
      // do segfault cleanup if any
      printf("%s: handling segfault\n", __func__);
    }
    else // abort
    {
      printf("%s: can't handle signal (%d)\n", __func__, throw_code);
      exit(throw_code);
    }
  }
  catch(int err)
  {
    if(err)
      throw(err);
  }
}

// seg fault uncorrected (fatal)
void test_unhandled()
{
  printf("Test 2 (unhandled segfault):\n");
  try
  {
    PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
    {
      char* s = 0;
      int c = *s;
      c = c; // use it
    }
    HANDLE(false)        // handle signals and flag = not continuing
    {
      printf("%s: not handling segfault\n", __func__);
      printf("%s: throwing code (1)\n", __func__);
      throw(1);
    }
    POP_HANDLER();      // end HANDLER block to continue execution
  }
  catch(int err)
  {
    if(err)
      throw(err);
  }
}

void tester()
{
  printf("%s: testing translating handled and unhandled signals to throw-catch\n", __func__);
  int caught = 0;
  try
  {
    PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
    {
      test_handled();
    }
    HANDLE(false)        // handle signals and flag = not continuing
    {
      printf("test_handled screwed up, supposed handle errors\n");
      printf("%s: HANDLE throwing code (4)\n", __func__);
      throw(4);
    }
    POP_HANDLER();      // end HANDLER block to continue execution
  }
  catch(int err)
  {
    caught = err;
  }
  // caught...
  try
  {
    PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
    {
      test_unhandled();
    }
    
    // this time we want to know if the signal was handled or not
    HANDLE(false)        // handle signals and flag = not continuing
    {
      printf("%s: can't handle throw_code = %d\n", __func__, throw_code);
      printf("%s: HANDLE throwing code (2)\n", __func__);
      throw(2);
    }
    POP_HANDLER();      // end HANDLER block to continue execution
  }
  catch(int err)
  {
    caught += 2;
  }
  if(caught)
  {
    printf("%s: caught cumulative error code(s) (%d)\n", __func__, caught);
    printf("%s: rethrowing throw_code (%d) from handler funcs\n", __func__, throw_code);
    if(caught)
      throw(throw_code);
  }
}

int main(int argc, char** argv)
{
  dbg();
  // done only once in main();
  BEGIN_MAIN_HANDLER(); // init system
  try
  {
    PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
    {
      tester();
    }
    HANDLE(false)        // handle signals and flag = not continuing
    {
      throw(1);
    }    
    POP_HANDLER();      // end HANDLER block to continue execution
  }
  catch(int err)
  {
    if(err)
    {
      printf("main: caught code (%d)\n", err);
    }
  }
  // done only once in main();
  END_MAIN_HANDLER(); // reset terminate function for throw-catch
    
  printf("Exiting main() normally after testing\n");
  return 0;
}
See the makefile tips in the next post if you want to build the C++ tests above.

Here's the straight C version. It does have the -std-gnu99 flag set but I don't remember if that's still needed or not as the code has evolved.

file: src/main.c
Code:
// main.c sig-handler test

/* 
  In the C version to avoid adding an additional PUSH_HANDLER/POP_HANDLER
  pair around the individual tests, we don't HANDLER_THROW() anything until 
  we leave the block, reading the handler_code to determine whether to throw 
  or not.
  
  As a result the HANDLE() functions set the continuing flag to true and 
  'catch' is simulated by reading the handler_code flag.  
  
*/

#include <stdio.h>  // printf(), FILE*, etc.
#include <malloc.h> // malloc(), free()
#include <string.h> // strcpy(), memcpy(), etc.

#include "signal-handler.h"

// these macros help show what the param in HANDLE(param)
// is doing.  It's only a flag for whether to unnest the 
// handlers or not within a HANDLE block.  True = continue
// i.e., NOT to unnest the HANDLER
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif


void dbg(){}

void noop() {}

// seg fault corrected
void test_handled()
{
  printf("Test 1 (handled segfault):\n");
    PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
    {
      char* s = 0;
      s += 9;
      int c = *s;
      c = c; // use it
    }
    HANDLE(true);       // handle signals and flag = continue normally
    POP_HANDLER();      // end HANDLER block to continue execution
    
    if(throw_code == 11)
    {
      // do segfault cleanup if any
      printf("%s: handling segfault\n", __func__);
    }
    else // abort
    {
      printf("%s: can't handle signal (%d)\n", __func__, throw_code);
      exit(throw_code);
    }
    if(handler_code)
      HANDLER_THROW(handler_code);
    else
      noop();
}

// seg fault uncorrected (fatal)
void test_unhandled()
{
  printf("Test 2 (unhandled segfault):\n");
    PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
    {
      char* s = 0;
      int c = *s;
      c = c; // use it
    }
    HANDLE(true)        // handle signals and flag = continuing
    {
      printf("%s: not handling segfault\n", __func__);
      printf("%s: throwing code (1)\n", __func__);
      handler_code = 1;
    }
    POP_HANDLER();      // end HANDLER block to continue execution
    if(handler_code)
      HANDLER_THROW(handler_code);
}

void tester()
{
  printf("%s: testing translating handled and unhandled signals to throw-catch\n", __func__);
  int caught = 0;
  PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
  {
    test_handled();
  }
  HANDLE(true)        // handle signals and flag = continuing
  {
    printf("test_handled screwed up, supposed handle errors\n");
    printf("%s: HANDLE throwing code (4)\n", __func__);
    handler_code = 4;
  }
  POP_HANDLER();      // end HANDLER block to continue execution
  if(handler_code)
    caught = handler_code;
    
  PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
  {
    test_unhandled();
  }
    
    // this time we want to know if the signal was handled or not
  HANDLE(true)        // handle signals and flag = continuing
  {
    printf("%s: can't handle throw_code = %d\n", __func__, throw_code);
    printf("%s: HANDLE throwing code (2)\n", __func__);
    handler_code = 2;
  }
  POP_HANDLER();      // end HANDLER block to continue execution
  
  if(handler_code)
    caught += handler_code;
  
  if(caught)
  {
    printf("%s: caught cumulative error code(s) (%d)\n", __func__, caught);
    printf("%s: rethrowing throw_code (%d) from handler funcs\n", __func__, throw_code);
    HANDLER_THROW(throw_code);
  }
}

int main(int argc, char** argv)
{
  dbg();
  // done only once in main();
  BEGIN_MAIN_HANDLER(); // init system
  PUSH_HANDLER()      // set up HANDLE(flg) as the signal hander
  {
    tester();
  }
  HANDLE(true)        // handle signals and flag = continuing
    handler_code = 1;
  POP_HANDLER();      // end HANDLER block to continue execution
  
  // done only once in main();
  END_MAIN_HANDLER(); // reset terminate function for throw-catch
    
  printf("Exiting main() normally after testing\n");
  return 0;
}
Cont'd in part 2
Posted in Uncategorized
Views 1087 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 11:46 PM.

Main Menu
Advertisement

My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration