View Issue Details

IDProjectCategoryView StatusLast Update
0002213ScribusInternalpublic2005-11-03 12:59
Reporterjghali Assigned Tojghali  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
PlatformWindowsOSWindowsOS Version2000 SP4
Product Version1.3.0cvs 
Fixed in Version1.3.2cvs 
Summary0002213: mscv compatibility for main.cpp
DescriptionThe attached diff allow main.cpp to compile on msvc. It deals with signals management. Most of the functions used (sigemptyset, sigaddset, sigprocmask...) are non existent on win32 and have no equivalent. I have looked at libgw32c to see how these functions were implemented. But define dummy functions and it's about the same. So it's what I've done... Just replaced the alarm() one ... If someone has a better solution...
(It may exists : http://www.cs.wustl.edu/~schmidt/ACE.html )
TagsNo tags attached.
Patch

Relationships

child of 0000015 closedjghali Windows Port 

Activities

ringerc

2005-07-10 02:30

reporter   ~0005474

Only affects win32, and looks ok except for a missing #ifdef _WIN32 around the VOID CALLBACK implementation. Merging.

ringerc

2005-07-10 02:35

reporter   ~0005475

Actually, I'll hold on this one and see what cbradney thinks - he might have an alternative to suggest. I'm not comfortable with just merging anything that #defines away functions, especially since those are not protected by #ifdef _WIN32 .

ringerc

2005-07-10 02:36

reporter   ~0005476

Reminder sent to: cbradney

Any thoughts on this one? I'm wondering if providing an alternative implementation for the body of the function doing all the setup might be better.

cbradney

2005-07-10 04:16

administrator   ~0005486

If the signals dont exist then they wont be sent. Better to not undefine and find a different solution. I will look at this today.

cbradney

2005-07-10 07:41

administrator   ~0005488

/***************************************************************************
                        main.cpp - description
                            -------------------
    begin : Fre Apr 6 21:47:55 CEST 2001
    copyright : (C) 2001 by Franz Schmid
    email : Franz.Schmid@altmuehlnet.de
    copyright : (C) 2004 by Alessandro Rimoldi
    email : http://ideale.ch/contact
    copyright : (C) 2005 by Craig Bradney
    email : cbradney@zip.com.au
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include <iostream>
#include <signal.h>

#include <qapplication.h>

#define BASE_QM "scribus"

#include "scribusapp.h"
#include "scribus.h"

#include "scconfig.h"

#ifdef _WIN32
 #include <windows.h>
 #ifndef SIG_UNBLOCK
  #define SIG_UNBLOCK 2
 #endif

 #ifndef SIGALRM
  #define SIGALRM 14
 #endif

  #ifndef sigset_t
  #define sigset_t int
 #endif

 #ifndef sigemptyset
  #define sigemptyset(sig)
 #endif

 #ifndef sigaddset
  #define sigaddset( set, sig)
 #endif

 #ifndef sigprocmask
  #define sigprocmask(a, b, c)
 #endif

 VOID CALLBACK raiseSigAlarm(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
 #define alarm(delay) SetTimer(NULL, NULL, delay, (TIMERPROC) raiseSigAlarm)
#endif

int mainApp(int argc, char **argv);
void initCrashHandler();
static void defaultCrashHandler(int sig);


ScribusApp* ScApp;
ScribusQApp* ScQApp;
bool emergencyActivated;

int main(int argc, char *argv[])
{
    return mainApp(argc, argv);
}

/*!
\fn int mainGui(int argc, char **argv)
\author Franz Schmid
\author Alessandro Rimoldi
\author Craig Bradney
\date Mon Feb 9 14:07:46 CET 2004
\brief Launches the Gui
\param int Number of arguments passed to Scribus
\param char *argv list of the arguments passed to Scribus
\retval int Error code from the execution of Scribus
*/
int mainApp(int argc, char **argv)
{
    emergencyActivated=false;
    ScribusQApp app(argc, argv);
    initCrashHandler();
    app.parseCommandLine();
    if (app.usingGUI())
    {
        int appRetVal=app.init();
        if (appRetVal==EXIT_FAILURE)
            return(EXIT_FAILURE);
        return app.exec();
    }
    return EXIT_SUCCESS;
}

void initCrashHandler()
{
    typedef void (*HandlerType)(int);
    HandlerType handler = 0;
    handler = defaultCrashHandler;
    if (!handler)
        handler = SIG_DFL;
    sigset_t mask;
    sigemptyset(&mask);
#ifdef SIGSEGV
    signal (SIGSEGV, handler);
    sigaddset(&mask, SIGSEGV);
#endif
#ifdef SIGFPE
    signal (SIGFPE, handler);
    sigaddset(&mask, SIGFPE);
#endif
#ifdef SIGILL
    signal (SIGILL, handler);
    sigaddset(&mask, SIGILL);
#endif
#ifdef SIGABRT
    signal (SIGABRT, handler);
    sigaddset(&mask, SIGABRT);
#endif
    sigprocmask(SIG_UNBLOCK, &mask, 0);
}

void defaultCrashHandler(int sig)
{
    static int crashRecursionCounter = 0;
    crashRecursionCounter++;
    signal(SIGALRM, SIG_DFL);
    if (crashRecursionCounter < 2)
    {
        emergencyActivated=true;
        crashRecursionCounter++;
        QString sigHdr=QObject::tr("Scribus Crash");
        QString sigLine="-------------";
        QString sigMsg=QObject::tr("Scribus crashes due to Signal #%1").arg(sig);
        std::cout << sigHdr << std::endl;
        std::cout << sigLine << std::endl;
        std::cout << sigMsg << std::endl;
        if (ScribusQApp::useGUI)
        {
            ScApp->closeSplash();
            QMessageBox::critical(ScApp, sigHdr, sigMsg, QObject::tr("&OK"));
            ScApp->emergencySave();
            ScApp->close();
        }
        alarm(300);
    }
    exit(255);
}

#ifdef _WIN32
VOID CALLBACK raiseSigAlarm(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
    raise(SIGALRM);
}
#endif

jghali

2005-07-10 07:46

administrator   ~0005489

As I said, if you have a better solution, I'll take it.

cbradney

2005-07-10 09:24

administrator   ~0005492

I dont at this point in time. Is there a call to be made to hook up the signal in Windows? like:
  typedef void (*HandlerType)(int);
  HandlerType handler = 0;
  handler = defaultCrashHandler;
in our current code? That seems to be missing if so.

Ringerc said he might have an idea re splitting it into a different function on Windows. At this points its probably sufficiently uncomplicated enough to not worry, but a tidier solution might be found.

jghali

2005-07-10 11:16

administrator   ~0005493

I'm looking on my side.

To my knowledge, the closest thing to what you mention requires use of MFC api. For a taste a the thing :
http://www.codeproject.com/dialog/messagehandling.asp
http://www.codeproject.com/dialog/messagehandling2.asp
Another thing... MFC... Beuaahhh!!!

POSIX style signal handling is quite minimal on Windows and is not availaible with Win32 api, only through C RTL. Here are the signal management functions defined in msvc signal.h
- int raise(int sig);
- void (__cdecl *signal(int sig, void (__cdecl *func )(int[,int ])))(int);
That's all...

jghali

2005-07-10 11:25

administrator   ~0005494

Last edited: 2005-07-10 12:07

Here are interesting threads :
http://archives.postgresql.org/pgsql-hackers-win32/2004-01/msg00003.php
http://archives.postgresql.org/pgsql-hackers-win32/2004-01/msg00069.php

jghali

2005-07-10 18:05

administrator   ~0005498

Asking myself if we need to crash our head about this subject, as SIGSEGV, SIGFPE, SIGILL and SIGABRT (etc...) are by default unblocked on win32... I've already observed a crash with message "Scribus crashes due to Signal 11" on my win32 build. If signals need to be blocked on win32, CriticalSection can be used...

jghali

2005-07-18 20:12

administrator   ~0005636

Last edited: 2005-07-18 21:34

Apparently on win32, exit() should not be called from a signal handler. So win32 defaultCrashHandler should be modified. Thinking to something like this :
- remove line signal(SIGALRM, SIG_DFL)
- remove line exit(255)
Then modify raiseSigAlarm():
- use exit() or SendMessage(hwnd, WM_CLOSE, ...) instead of raise()
- rename raiseSigAlarm into something more meaningful
Comments???

jghali

2005-07-19 07:05

administrator   ~0005639

Additionnaly, on win32, SIGINT is not supported for Win32 application. See :
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_CRT_signal.asp
The Win32 release build will be compiled with _WINDOWS directive and standard streams redirected to display in a debug window.

jghali

2005-07-19 11:42

administrator   ~0005640

Additionnaly, according to msdn, the SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows NT. They are included for ANSI compatibility and should be raised explicitly.

jghali

2005-07-23 21:16

administrator   ~0005678

I think I've found a satisfying crash handler for win32. Instead of using exit() in defaultCrashHandler it throws a runtime_error exception which is catched in main(). It works on win32, does it on *nix? The modified main has been uploaded (main_except.cpp).

Additionnaly, some info about signal handling on win32 : signal handlers are never inherited by child processes. So on win32, all sigaddset, sigemptyset, sigprocmask are not useful in this case.

ringerc

2005-07-24 06:09

reporter   ~0005686

Qt on some (most?) Linux distros is compiled without exceptions. Additionally, Scribus isn't really ready to be built with exception support (a *lot* of 'new' calls need to be changed to new (nothrow) ... or fixed up, for example).

Personally, I don't know *why* as I came from the Python world were excepions are something utterly fundamental, but it seems a lot of C++ folks don't like them and think they cause memory bloat. It's not a debate I'm really intersted in getting into, and I don't know the right answer.

I'm not sure, however, that relying on exceptions for core error handling is wise given that some vendors will just turn it off. I don't know much about C++ exceptions. Can we safely work with a Qt built without exceptions when we enable exceptions? Will we pay a big penalty in memory consumption from exceptions or has that been cleaned up in more recentlt compilers?

ringerc

2005-07-24 06:17

reporter   ~0005687

A quick chat on the #KDE suggests that exceptions, at least with gcc, are more acceptable efficiency-wise than they used to be. Apparently they're OK to use with code that doesn't support exceptions so long as you don't throw exceptions "through" code - such as the Qt event loop - that doesn't understand them.

I presume that'll be because that code won't have the appropriate compiler-generated code for detecting the exception, cleaning up, and returning properly.

This means that they're likely to be OK for things like

void doSomethingBig()
{
   try
      ... long list of statements ...
   catch something
      ... and clean up

}

but probably *not* for transferring control around large bits of the program. In addition to not throwing through the Qt event loop I think we'd also have to watch out for throwing through signal/slot dispatch, which given Scribus's heavy use of signals and slots even when simple function calls are more appropriate would be a serious problem.

jghali

2005-07-24 13:51

administrator   ~0005694

Hum... Going to find another way of doing the thing then...

ringerc

2005-10-29 08:01

reporter   ~0007249

I've done a little more reading on the use of exceptions on win32. It looks like win32 uses its underlying structured exception handling (SEH) mechanism to implement C++ exceptions. Since SEH is used to handle things like segmentation violations, it looks like they extended the C++ exception support to permit you to "catch" a segfault, etc.

This won't work on Linux, as the implementation of exceptions in gcc is different, and doesn't map the POSIX signals the OS uses to inform apps about such problems to exceptions.

It may be possible to use SEH on win32 to handle these conditions, without going for full C++ exception support. Here's some info on SEH, in case it's useful: http://www.microsoft.com/msj/0197/exception/exception.aspx

jghali

2005-10-30 14:53

administrator   ~0007267

I have coded a new main.cpp (main_win.cpp) using structured exceptions. Seems to work well. Will test further before submiting.

2005-11-02 22:02

 

main_win.cpp (6,877 bytes)   
/***************************************************************************
						main.cpp  -  description
							-------------------
	begin                : Fre Apr  6 21:47:55 CEST 2001
	copyright            : (C) 2001 by Franz Schmid
	email                : Franz.Schmid@altmuehlnet.de
	copyright            : (C) 2004 by Alessandro Rimoldi
	email                : http://ideale.ch/contact
	copyright            : (C) 2005 by Craig Bradney
	email                : cbradney@zip.com.au
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/

#include <iostream>
#include <signal.h>

#ifndef _WIN32
#error "This file compiles on win32 platform only"
#endif

#include <qapplication.h>
#include <exception>
using namespace std;

#define BASE_QM "scribus"

#include "scribusapp.h"
#include "scribus.h"

#include "scconfig.h"

#include <windows.h>

int mainApp(ScribusQApp& app);
static LONG exceptionFilter(DWORD exceptionCode);
static QString exceptionDescription(DWORD exceptionCode);
static void defaultCrashHandler(DWORD exceptionCode);

ScribusApp SCRIBUS_API *ScApp;
ScribusQApp SCRIBUS_API *ScQApp;
bool emergencyActivated;

int main(int argc, char *argv[])
{
	int result;
	emergencyActivated = false;
	ScribusQApp app(argc, argv);
	result =  mainApp(app);
	return result;
}

/*!
\fn int mainApp(ScribusQApp& app)
\author Franz Schmid
\author Alessandro Rimoldi
\author Craig Bradney
\author Jean Ghali
\date Mon Feb  9 14:07:46 CET 2004
\brief Launches the Gui
\param ScribusQApp& app a Scribus QApplication object
\retval int Error code from the execution of Scribus
*/
int mainApp(ScribusQApp& app)
{
	int appRetVal;
	__try
	{
		app.parseCommandLine();
		if (app.usingGUI())
		{
			appRetVal = app.init();
			if (appRetVal != EXIT_FAILURE)
				appRetVal = app.exec();
		}
	}
	__except( exceptionFilter(GetExceptionCode()) )
	{
		defaultCrashHandler( GetExceptionCode() );
	}
	return appRetVal;
}

/*!
\fn int exceptionFilter(DWORD exceptionCode)
\author Jean Ghali
\date Sun Oct 30 14:30:30 CET 2005
\brief describe the behavior to be adopted against specific exception
\param DWORD exceptionCode the value returned by GetExceptionCode()
\retval EXCEPTION_EXECUTE_HANDLER if handler is to be executed or EXCEPTION_CONTINUE_EXECUTION if not
*/
LONG exceptionFilter(DWORD exceptionCode)
{
 LONG result; 
	switch( exceptionCode )
	{
	case EXCEPTION_ACCESS_VIOLATION:
	case EXCEPTION_DATATYPE_MISALIGNMENT:
	case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
	case EXCEPTION_FLT_DENORMAL_OPERAND:
	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
	case EXCEPTION_FLT_INEXACT_RESULT:
	case EXCEPTION_FLT_INVALID_OPERATION:
	case EXCEPTION_FLT_OVERFLOW:
	case EXCEPTION_FLT_STACK_CHECK:
	case EXCEPTION_FLT_UNDERFLOW:
	case EXCEPTION_ILLEGAL_INSTRUCTION:
	case EXCEPTION_INT_DIVIDE_BY_ZERO:
	case EXCEPTION_INT_OVERFLOW:
	case EXCEPTION_INVALID_HANDLE:
	case EXCEPTION_NONCONTINUABLE_EXCEPTION:
	case EXCEPTION_STACK_OVERFLOW:
		result = EXCEPTION_EXECUTE_HANDLER;
		break;
	case EXCEPTION_BREAKPOINT:
	case EXCEPTION_SINGLE_STEP:
		result = EXCEPTION_CONTINUE_EXECUTION;
		break;
	default:
		result = EXCEPTION_EXECUTE_HANDLER;
		break;
	}
	return result;
}

/*!
\fn int exceptionDescription(DWORD exceptionCode)
\author Jean Ghali
\date Sun Oct 30 14:30:30 CET 2005
\brief return a string describing a specific exception
\param DWORD exceptionCode the value returned by GetExceptionCode()
\retval string describing the specified exception
*/
static QString exceptionDescription(DWORD exceptionCode)
{
 QString description;
	if ( exceptionCode == EXCEPTION_ACCESS_VIOLATION )
		description = "EXCEPTION_ACCESS_VIOLATION";
	else if ( exceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT )
		description = "EXCEPTION_DATATYPE_MISALIGNMENT";
	else if ( exceptionCode == EXCEPTION_ARRAY_BOUNDS_EXCEEDED )
		description = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
	else if ( exceptionCode == EXCEPTION_FLT_DENORMAL_OPERAND )
		description = "EXCEPTION_FLT_DENORMAL_OPERAND";
	else if ( exceptionCode == EXCEPTION_FLT_DIVIDE_BY_ZERO )
		description = "EXCEPTION_FLT_DIVIDE_BY_ZERO";
	else if ( exceptionCode == EXCEPTION_FLT_INEXACT_RESULT )
		description = "EXCEPTION_FLT_INEXACT_RESULT";
	else if ( exceptionCode == EXCEPTION_FLT_INVALID_OPERATION )
		description = "EXCEPTION_FLT_INVALID_OPERATION";
	else if ( exceptionCode == EXCEPTION_FLT_OVERFLOW )
		description = "EXCEPTION_FLT_OVERFLOW";
	else if ( exceptionCode == EXCEPTION_FLT_STACK_CHECK )
		description = "EXCEPTION_FLT_STACK_CHECK";
	else if ( exceptionCode == EXCEPTION_FLT_UNDERFLOW )
		description = "EXCEPTION_FLT_UNDERFLOW";
	else if ( exceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION )
		description = "EXCEPTION_ILLEGAL_INSTRUCTION";
	else if ( exceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO )
		description = "EXCEPTION_INT_DIVIDE_BY_ZERO";
	else if ( exceptionCode == EXCEPTION_INT_OVERFLOW )
		description = "EXCEPTION_INT_OVERFLOW";
	else if ( exceptionCode == EXCEPTION_INVALID_HANDLE )
		description = "EXCEPTION_INVALID_HANDLE";
	else if ( exceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION )
		description = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
	else if ( exceptionCode == EXCEPTION_STACK_OVERFLOW )
		description = "EXCEPTION_STACK_OVERFLOW";
	else
		description = "UNKNOWN EXCEPTION";
	return description;
}

void defaultCrashHandler(DWORD exceptionCode)
{
	static int crashRecursionCounter = 0;
	crashRecursionCounter++;
	if (crashRecursionCounter < 2)
	{
		emergencyActivated=true;
		crashRecursionCounter++;
		QString expDesc = exceptionDescription(exceptionCode);
		QString expHdr=QObject::tr("Scribus Crash");
		QString expLine="-------------";
		QString expMsg=QObject::tr("Scribus crashes due to the following exception : %1").arg(expDesc);
		std::cout << (const char*) expHdr << std::endl;
		std::cout << (const char*) expLine << std::endl;
		std::cout << (const char*) expMsg << std::endl;
		if (ScribusQApp::useGUI)
		{
			ScApp->closeSplash();
			QMessageBox::critical(ScApp, expHdr, expMsg, QObject::tr("&OK"));
			ScApp->emergencySave();
			ScApp->close();
		}
	}
	ExitProcess(255);
}
main_win.cpp (6,877 bytes)   

jghali

2005-11-02 22:04

administrator   ~0007312

Last edited: 2005-11-02 22:10

I've uploaded the new main for windows (main_win.cpp).

Issue History

Date Modified Username Field Change
2005-07-09 21:35 jghali New Issue
2005-07-09 21:35 jghali File Added: main_signals_13x.diff
2005-07-10 02:30 ringerc Note Added: 0005474
2005-07-10 02:35 ringerc Note Added: 0005475
2005-07-10 02:35 ringerc Status new => acknowledged
2005-07-10 02:36 ringerc Note Added: 0005476
2005-07-10 04:16 cbradney Note Added: 0005486
2005-07-10 04:17 cbradney Status acknowledged => assigned
2005-07-10 04:17 cbradney Assigned To => cbradney
2005-07-10 07:41 cbradney Note Added: 0005488
2005-07-10 07:46 jghali Note Added: 0005489
2005-07-10 09:24 cbradney Note Added: 0005492
2005-07-10 11:16 jghali Note Added: 0005493
2005-07-10 11:25 jghali Note Added: 0005494
2005-07-10 12:07 jghali Note Edited: 0005494
2005-07-10 18:05 jghali Note Added: 0005498
2005-07-15 07:40 ringerc Relationship added related to 0000015
2005-07-15 07:41 ringerc Relationship replaced child of 0000015
2005-07-18 20:12 jghali Note Added: 0005636
2005-07-18 21:32 jghali Note Edited: 0005636
2005-07-18 21:34 jghali Note Edited: 0005636
2005-07-19 07:05 jghali Note Added: 0005639
2005-07-19 11:42 jghali Note Added: 0005640
2005-07-23 21:03 jghali File Added: main_except.cpp
2005-07-23 21:16 jghali Note Added: 0005678
2005-07-24 06:09 ringerc Note Added: 0005686
2005-07-24 06:17 ringerc Note Added: 0005687
2005-07-24 13:51 jghali Note Added: 0005694
2005-08-30 11:55 cbradney Assigned To cbradney => jghali
2005-10-29 08:01 ringerc Note Added: 0007249
2005-10-30 14:53 jghali Note Added: 0007267
2005-11-02 22:02 jghali File Added: main_win.cpp
2005-11-02 22:02 jghali File Deleted: main_signals_13x.diff
2005-11-02 22:02 jghali File Deleted: main_except.cpp
2005-11-02 22:04 jghali Note Added: 0007312
2005-11-02 22:10 jghali Note Edited: 0007312
2005-11-03 00:23 cbradney Status assigned => resolved
2005-11-03 00:23 cbradney Fixed in Version => 1.3.2cvs
2005-11-03 00:23 cbradney Resolution open => fixed
2005-11-03 12:59 jghali Status resolved => closed